Home | History | Annotate | Download | only in surfaceflinger_client
      1 /*
      2  * Copyright (C) 2007 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 "SharedBufferStack"
     18 
     19 #include <stdint.h>
     20 #include <sys/types.h>
     21 
     22 #include <utils/Debug.h>
     23 #include <utils/Log.h>
     24 #include <utils/threads.h>
     25 
     26 #include <private/surfaceflinger/SharedBufferStack.h>
     27 
     28 #include <ui/Rect.h>
     29 #include <ui/Region.h>
     30 
     31 #define DEBUG_ATOMICS 0
     32 
     33 namespace android {
     34 // ----------------------------------------------------------------------------
     35 
     36 SharedClient::SharedClient()
     37     : lock(Mutex::SHARED), cv(Condition::SHARED)
     38 {
     39 }
     40 
     41 SharedClient::~SharedClient() {
     42 }
     43 
     44 
     45 // these functions are used by the clients
     46 status_t SharedClient::validate(size_t i) const {
     47     if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX))
     48         return BAD_INDEX;
     49     return surfaces[i].status;
     50 }
     51 
     52 uint32_t SharedClient::getIdentity(size_t token) const {
     53     return uint32_t(surfaces[token].identity);
     54 }
     55 
     56 // ----------------------------------------------------------------------------
     57 
     58 
     59 SharedBufferStack::SharedBufferStack()
     60 {
     61 }
     62 
     63 void SharedBufferStack::init(int32_t i)
     64 {
     65     inUse = -1;
     66     status = NO_ERROR;
     67     identity = i;
     68 }
     69 
     70 status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
     71 {
     72     if (uint32_t(buffer) >= NUM_BUFFER_MAX)
     73         return BAD_INDEX;
     74 
     75     // in the current implementation we only send a single rectangle
     76     const Rect bounds(dirty.getBounds());
     77     FlatRegion& reg(dirtyRegion[buffer]);
     78     reg.count = 1;
     79     reg.rects[0] = uint16_t(bounds.left);
     80     reg.rects[1] = uint16_t(bounds.top);
     81     reg.rects[2] = uint16_t(bounds.right);
     82     reg.rects[3] = uint16_t(bounds.bottom);
     83     return NO_ERROR;
     84 }
     85 
     86 Region SharedBufferStack::getDirtyRegion(int buffer) const
     87 {
     88     Region res;
     89     if (uint32_t(buffer) >= NUM_BUFFER_MAX)
     90         return res;
     91 
     92     const FlatRegion& reg(dirtyRegion[buffer]);
     93     res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3]));
     94     return res;
     95 }
     96 
     97 // ----------------------------------------------------------------------------
     98 
     99 SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
    100         int surface, int num, int32_t identity)
    101     : mSharedClient(sharedClient),
    102       mSharedStack(sharedClient->surfaces + surface),
    103       mNumBuffers(num), mIdentity(identity)
    104 {
    105 }
    106 
    107 SharedBufferBase::~SharedBufferBase()
    108 {
    109 }
    110 
    111 uint32_t SharedBufferBase::getIdentity()
    112 {
    113     SharedBufferStack& stack( *mSharedStack );
    114     return stack.identity;
    115 }
    116 
    117 status_t SharedBufferBase::getStatus() const
    118 {
    119     SharedBufferStack& stack( *mSharedStack );
    120     return stack.status;
    121 }
    122 
    123 size_t SharedBufferBase::getFrontBuffer() const
    124 {
    125     SharedBufferStack& stack( *mSharedStack );
    126     return size_t( stack.head );
    127 }
    128 
    129 String8 SharedBufferBase::dump(char const* prefix) const
    130 {
    131     const size_t SIZE = 1024;
    132     char buffer[SIZE];
    133     String8 result;
    134     SharedBufferStack& stack( *mSharedStack );
    135     int tail = (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
    136     snprintf(buffer, SIZE,
    137             "%s[ head=%2d, available=%2d, queued=%2d, tail=%2d ] "
    138             "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n",
    139             prefix, stack.head, stack.available, stack.queued, tail,
    140             stack.reallocMask, stack.inUse, stack.identity, stack.status);
    141     result.append(buffer);
    142     return result;
    143 }
    144 
    145 // ============================================================================
    146 // conditions and updates
    147 // ============================================================================
    148 
    149 SharedBufferClient::DequeueCondition::DequeueCondition(
    150         SharedBufferClient* sbc) : ConditionBase(sbc)  {
    151 }
    152 bool SharedBufferClient::DequeueCondition::operator()() {
    153     return stack.available > 0;
    154 }
    155 
    156 SharedBufferClient::LockCondition::LockCondition(
    157         SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
    158 }
    159 bool SharedBufferClient::LockCondition::operator()() {
    160     return (buf != stack.head ||
    161             (stack.queued > 0 && stack.inUse != buf));
    162 }
    163 
    164 SharedBufferServer::ReallocateCondition::ReallocateCondition(
    165         SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) {
    166 }
    167 bool SharedBufferServer::ReallocateCondition::operator()() {
    168     // TODO: we should also check that buf has been dequeued
    169     return (buf != stack.head);
    170 }
    171 
    172 // ----------------------------------------------------------------------------
    173 
    174 SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
    175     : UpdateBase(sbb) {
    176 }
    177 ssize_t SharedBufferClient::QueueUpdate::operator()() {
    178     android_atomic_inc(&stack.queued);
    179     return NO_ERROR;
    180 }
    181 
    182 SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb)
    183     : UpdateBase(sbb) {
    184 }
    185 ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() {
    186     android_atomic_inc(&stack.available);
    187     return NO_ERROR;
    188 }
    189 
    190 SharedBufferServer::UnlockUpdate::UnlockUpdate(
    191         SharedBufferBase* sbb, int lockedBuffer)
    192     : UpdateBase(sbb), lockedBuffer(lockedBuffer) {
    193 }
    194 ssize_t SharedBufferServer::UnlockUpdate::operator()() {
    195     if (stack.inUse != lockedBuffer) {
    196         LOGE("unlocking %d, but currently locked buffer is %d",
    197                 lockedBuffer, stack.inUse);
    198         return BAD_VALUE;
    199     }
    200     android_atomic_write(-1, &stack.inUse);
    201     return NO_ERROR;
    202 }
    203 
    204 SharedBufferServer::RetireUpdate::RetireUpdate(
    205         SharedBufferBase* sbb, int numBuffers)
    206     : UpdateBase(sbb), numBuffers(numBuffers) {
    207 }
    208 ssize_t SharedBufferServer::RetireUpdate::operator()() {
    209     // head is only written in this function, which is single-thread.
    210     int32_t head = stack.head;
    211 
    212     // Preventively lock the current buffer before updating queued.
    213     android_atomic_write(head, &stack.inUse);
    214 
    215     // Decrement the number of queued buffers
    216     int32_t queued;
    217     do {
    218         queued = stack.queued;
    219         if (queued == 0) {
    220             return NOT_ENOUGH_DATA;
    221         }
    222     } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
    223 
    224     // update the head pointer
    225     head = ((head+1 >= numBuffers) ? 0 : head+1);
    226 
    227     // lock the buffer before advancing head, which automatically unlocks
    228     // the buffer we preventively locked upon entering this function
    229     android_atomic_write(head, &stack.inUse);
    230 
    231     // advance head
    232     android_atomic_write(head, &stack.head);
    233 
    234     // now that head has moved, we can increment the number of available buffers
    235     android_atomic_inc(&stack.available);
    236     return head;
    237 }
    238 
    239 SharedBufferServer::StatusUpdate::StatusUpdate(
    240         SharedBufferBase* sbb, status_t status)
    241     : UpdateBase(sbb), status(status) {
    242 }
    243 
    244 ssize_t SharedBufferServer::StatusUpdate::operator()() {
    245     android_atomic_write(status, &stack.status);
    246     return NO_ERROR;
    247 }
    248 
    249 // ============================================================================
    250 
    251 SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
    252         int surface, int num, int32_t identity)
    253     : SharedBufferBase(sharedClient, surface, num, identity), tail(0)
    254 {
    255     tail = computeTail();
    256 }
    257 
    258 int32_t SharedBufferClient::computeTail() const
    259 {
    260     SharedBufferStack& stack( *mSharedStack );
    261     // we need to make sure we read available and head coherently,
    262     // w.r.t RetireUpdate.
    263     int32_t newTail;
    264     int32_t avail;
    265     int32_t head;
    266     do {
    267         avail = stack.available;
    268         head = stack.head;
    269     } while (stack.available != avail);
    270     newTail = head - avail + 1;
    271     if (newTail < 0) {
    272         newTail += mNumBuffers;
    273     } else if (newTail >= mNumBuffers) {
    274         newTail -= mNumBuffers;
    275     }
    276     return newTail;
    277 }
    278 
    279 ssize_t SharedBufferClient::dequeue()
    280 {
    281     SharedBufferStack& stack( *mSharedStack );
    282 
    283     if (stack.head == tail && stack.available == 2) {
    284         LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
    285                 tail, stack.head, stack.available, stack.queued);
    286     }
    287 
    288     const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
    289 
    290     //LOGD("[%d] about to dequeue a buffer",
    291     //        mSharedStack->identity);
    292     DequeueCondition condition(this);
    293     status_t err = waitForCondition(condition);
    294     if (err != NO_ERROR)
    295         return ssize_t(err);
    296 
    297     // NOTE: 'stack.available' is part of the conditions, however
    298     // decrementing it, never changes any conditions, so we don't need
    299     // to do this as part of an update.
    300     if (android_atomic_dec(&stack.available) == 0) {
    301         LOGW("dequeue probably called from multiple threads!");
    302     }
    303 
    304     int dequeued = tail;
    305     tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
    306     LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
    307             dequeued, tail, dump("").string());
    308 
    309     mDequeueTime[dequeued] = dequeueTime;
    310 
    311     return dequeued;
    312 }
    313 
    314 status_t SharedBufferClient::undoDequeue(int buf)
    315 {
    316     UndoDequeueUpdate update(this);
    317     status_t err = updateCondition( update );
    318     if (err == NO_ERROR) {
    319         tail = computeTail();
    320     }
    321     return err;
    322 }
    323 
    324 status_t SharedBufferClient::lock(int buf)
    325 {
    326     LockCondition condition(this, buf);
    327     status_t err = waitForCondition(condition);
    328     return err;
    329 }
    330 
    331 status_t SharedBufferClient::queue(int buf)
    332 {
    333     QueueUpdate update(this);
    334     status_t err = updateCondition( update );
    335     LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
    336     SharedBufferStack& stack( *mSharedStack );
    337     const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
    338     stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
    339     return err;
    340 }
    341 
    342 bool SharedBufferClient::needNewBuffer(int buffer) const
    343 {
    344     SharedBufferStack& stack( *mSharedStack );
    345     const uint32_t mask = 1<<buffer;
    346     return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
    347 }
    348 
    349 status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg)
    350 {
    351     SharedBufferStack& stack( *mSharedStack );
    352     return stack.setDirtyRegion(buffer, reg);
    353 }
    354 
    355 // ----------------------------------------------------------------------------
    356 
    357 SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
    358         int surface, int num, int32_t identity)
    359     : SharedBufferBase(sharedClient, surface, num, identity)
    360 {
    361     mSharedStack->init(identity);
    362     mSharedStack->head = num-1;
    363     mSharedStack->available = num;
    364     mSharedStack->queued = 0;
    365     mSharedStack->reallocMask = 0;
    366     memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion));
    367 }
    368 
    369 ssize_t SharedBufferServer::retireAndLock()
    370 {
    371     RetireUpdate update(this, mNumBuffers);
    372     ssize_t buf = updateCondition( update );
    373     LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string());
    374     return buf;
    375 }
    376 
    377 status_t SharedBufferServer::unlock(int buffer)
    378 {
    379     UnlockUpdate update(this, buffer);
    380     status_t err = updateCondition( update );
    381     return err;
    382 }
    383 
    384 void SharedBufferServer::setStatus(status_t status)
    385 {
    386     if (status < NO_ERROR) {
    387         StatusUpdate update(this, status);
    388         updateCondition( update );
    389     }
    390 }
    391 
    392 status_t SharedBufferServer::reallocate()
    393 {
    394     SharedBufferStack& stack( *mSharedStack );
    395     uint32_t mask = (1<<mNumBuffers)-1;
    396     android_atomic_or(mask, &stack.reallocMask);
    397     return NO_ERROR;
    398 }
    399 
    400 int32_t SharedBufferServer::getQueuedCount() const
    401 {
    402     SharedBufferStack& stack( *mSharedStack );
    403     return stack.queued;
    404 }
    405 
    406 status_t SharedBufferServer::assertReallocate(int buffer)
    407 {
    408     ReallocateCondition condition(this, buffer);
    409     status_t err = waitForCondition(condition);
    410     return err;
    411 }
    412 
    413 Region SharedBufferServer::getDirtyRegion(int buffer) const
    414 {
    415     SharedBufferStack& stack( *mSharedStack );
    416     return stack.getDirtyRegion(buffer);
    417 }
    418 
    419 SharedBufferStack::Statistics SharedBufferServer::getStats() const
    420 {
    421     SharedBufferStack& stack( *mSharedStack );
    422     return stack.stats;
    423 }
    424 
    425 
    426 // ---------------------------------------------------------------------------
    427 }; // namespace android
    428