Home | History | Annotate | Download | only in surfaceflinger
      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 #ifndef ANDROID_SF_SHARED_BUFFER_STACK_H
     18 #define ANDROID_SF_SHARED_BUFFER_STACK_H
     19 
     20 #include <stdint.h>
     21 #include <sys/types.h>
     22 
     23 #include <cutils/compiler.h>
     24 
     25 #include <utils/Debug.h>
     26 #include <utils/threads.h>
     27 #include <utils/String8.h>
     28 
     29 #include <ui/Rect.h>
     30 
     31 namespace android {
     32 // ---------------------------------------------------------------------------
     33 
     34 /*
     35  * These classes manage a stack of buffers in shared memory.
     36  *
     37  * SharedClient: represents a client with several stacks
     38  * SharedBufferStack: represents a stack of buffers
     39  * SharedBufferClient: manipulates the SharedBufferStack from the client side
     40  * SharedBufferServer: manipulates the SharedBufferStack from the server side
     41  *
     42  * Buffers can be dequeued until there are none available, they can be locked
     43  * unless they are in use by the server, which is only the case for the last
     44  * dequeue-able buffer. When these various conditions are not met, the caller
     45  * waits until the condition is met.
     46  *
     47  *
     48  * CAVEATS:
     49  *
     50  * In the current implementation there are several limitations:
     51  * - buffers must be locked in the same order they've been dequeued
     52  * - buffers must be enqueued in the same order they've been locked
     53  * - dequeue() is not reentrant
     54  * - no error checks are done on the condition above
     55  *
     56  */
     57 
     58 // When changing these values, the COMPILE_TIME_ASSERT at the end of this
     59 // file need to be updated.
     60 const unsigned int NUM_LAYERS_MAX  = 31;
     61 const unsigned int NUM_BUFFER_MAX  = 4;
     62 const unsigned int NUM_DISPLAY_MAX = 4;
     63 
     64 // ----------------------------------------------------------------------------
     65 
     66 class Region;
     67 class SharedBufferStack;
     68 class SharedClient;
     69 
     70 // ----------------------------------------------------------------------------
     71 
     72 // should be 128 bytes (32 longs)
     73 class SharedBufferStack
     74 {
     75     friend class SharedClient;
     76     friend class SharedBufferBase;
     77     friend class SharedBufferClient;
     78     friend class SharedBufferServer;
     79 
     80 public:
     81     struct FlatRegion { // 12 bytes
     82         static const unsigned int NUM_RECT_MAX = 1;
     83         uint32_t    count;
     84         uint16_t    rects[4*NUM_RECT_MAX];
     85     };
     86 
     87     struct Statistics { // 4 longs
     88         typedef int32_t usecs_t;
     89         usecs_t  totalTime;
     90         usecs_t  reserved[3];
     91     };
     92 
     93     SharedBufferStack();
     94     void init(int32_t identity);
     95     status_t setDirtyRegion(int buffer, const Region& reg);
     96     Region getDirtyRegion(int buffer) const;
     97 
     98     // these attributes are part of the conditions/updates
     99     volatile int32_t head;      // server's current front buffer
    100     volatile int32_t available; // number of dequeue-able buffers
    101     volatile int32_t queued;    // number of buffers waiting for post
    102     volatile int32_t inUse;     // buffer currently in use by SF
    103     volatile status_t status;   // surface's status code
    104 
    105     // not part of the conditions
    106     volatile int32_t reallocMask;
    107 
    108     int32_t     identity;       // surface's identity (const)
    109     int32_t     reserved32[9];
    110     Statistics  stats;
    111     FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
    112 };
    113 
    114 // ----------------------------------------------------------------------------
    115 
    116 // 4 KB max
    117 class SharedClient
    118 {
    119 public:
    120     SharedClient();
    121     ~SharedClient();
    122 
    123     status_t validate(size_t token) const;
    124     uint32_t getIdentity(size_t token) const;
    125 
    126 private:
    127     friend class SharedBufferBase;
    128     friend class SharedBufferClient;
    129     friend class SharedBufferServer;
    130 
    131     // FIXME: this should be replaced by a lock-less primitive
    132     Mutex lock;
    133     Condition cv;
    134     SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
    135 };
    136 
    137 // ============================================================================
    138 
    139 class SharedBufferBase
    140 {
    141 public:
    142     SharedBufferBase(SharedClient* sharedClient, int surface, int num,
    143             int32_t identity);
    144     ~SharedBufferBase();
    145     uint32_t getIdentity();
    146     status_t getStatus() const;
    147     size_t getFrontBuffer() const;
    148     String8 dump(char const* prefix) const;
    149 
    150 protected:
    151     SharedClient* const mSharedClient;
    152     SharedBufferStack* const mSharedStack;
    153     const int mNumBuffers;
    154     const int mIdentity;
    155 
    156     friend struct Update;
    157     friend struct QueueUpdate;
    158 
    159     struct ConditionBase {
    160         SharedBufferStack& stack;
    161         inline ConditionBase(SharedBufferBase* sbc)
    162             : stack(*sbc->mSharedStack) { }
    163     };
    164 
    165     struct UpdateBase {
    166         SharedBufferStack& stack;
    167         inline UpdateBase(SharedBufferBase* sbb)
    168             : stack(*sbb->mSharedStack) { }
    169     };
    170 
    171     template <typename T>
    172     status_t waitForCondition(T condition);
    173 
    174     template <typename T>
    175     status_t updateCondition(T update);
    176 };
    177 
    178 template <typename T>
    179 status_t SharedBufferBase::waitForCondition(T condition)
    180 {
    181     const SharedBufferStack& stack( *mSharedStack );
    182     SharedClient& client( *mSharedClient );
    183     const nsecs_t TIMEOUT = s2ns(1);
    184     Mutex::Autolock _l(client.lock);
    185     while ((condition()==false) &&
    186             (stack.identity == mIdentity) &&
    187             (stack.status == NO_ERROR))
    188     {
    189         status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
    190 
    191         // handle errors and timeouts
    192         if (CC_UNLIKELY(err != NO_ERROR)) {
    193             if (err == TIMED_OUT) {
    194                 if (condition()) {
    195                     LOGE("waitForCondition(%s) timed out (identity=%d), "
    196                         "but condition is true! We recovered but it "
    197                         "shouldn't happen." , T::name(),
    198                         stack.identity);
    199                     break;
    200                 } else {
    201                     LOGW("waitForCondition(%s) timed out "
    202                         "(identity=%d, status=%d). "
    203                         "CPU may be pegged. trying again.", T::name(),
    204                         stack.identity, stack.status);
    205                 }
    206             } else {
    207                 LOGE("waitForCondition(%s) error (%s) ",
    208                         T::name(), strerror(-err));
    209                 return err;
    210             }
    211         }
    212     }
    213     return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
    214 }
    215 
    216 
    217 template <typename T>
    218 status_t SharedBufferBase::updateCondition(T update) {
    219     SharedClient& client( *mSharedClient );
    220     Mutex::Autolock _l(client.lock);
    221     ssize_t result = update();
    222     client.cv.broadcast();
    223     return result;
    224 }
    225 
    226 // ----------------------------------------------------------------------------
    227 
    228 class SharedBufferClient : public SharedBufferBase
    229 {
    230 public:
    231     SharedBufferClient(SharedClient* sharedClient, int surface, int num,
    232             int32_t identity);
    233 
    234     ssize_t dequeue();
    235     status_t undoDequeue(int buf);
    236 
    237     status_t lock(int buf);
    238     status_t queue(int buf);
    239     bool needNewBuffer(int buffer) const;
    240     status_t setDirtyRegion(int buffer, const Region& reg);
    241 
    242 private:
    243     friend struct Condition;
    244     friend struct DequeueCondition;
    245     friend struct LockCondition;
    246 
    247     int32_t computeTail() const;
    248 
    249     struct QueueUpdate : public UpdateBase {
    250         inline QueueUpdate(SharedBufferBase* sbb);
    251         inline ssize_t operator()();
    252     };
    253 
    254     struct UndoDequeueUpdate : public UpdateBase {
    255         inline UndoDequeueUpdate(SharedBufferBase* sbb);
    256         inline ssize_t operator()();
    257     };
    258 
    259     // --
    260 
    261     struct DequeueCondition : public ConditionBase {
    262         inline DequeueCondition(SharedBufferClient* sbc);
    263         inline bool operator()();
    264         static inline const char* name() { return "DequeueCondition"; }
    265     };
    266 
    267     struct LockCondition : public ConditionBase {
    268         int buf;
    269         inline LockCondition(SharedBufferClient* sbc, int buf);
    270         inline bool operator()();
    271         static inline const char* name() { return "LockCondition"; }
    272     };
    273 
    274     int32_t tail;
    275     // statistics...
    276     nsecs_t mDequeueTime[NUM_BUFFER_MAX];
    277 };
    278 
    279 // ----------------------------------------------------------------------------
    280 
    281 class SharedBufferServer : public SharedBufferBase
    282 {
    283 public:
    284     SharedBufferServer(SharedClient* sharedClient, int surface, int num,
    285             int32_t identity);
    286 
    287     ssize_t retireAndLock();
    288     status_t unlock(int buffer);
    289     void setStatus(status_t status);
    290     status_t reallocate();
    291     status_t assertReallocate(int buffer);
    292     int32_t getQueuedCount() const;
    293 
    294     Region getDirtyRegion(int buffer) const;
    295 
    296     SharedBufferStack::Statistics getStats() const;
    297 
    298 
    299 private:
    300     struct UnlockUpdate : public UpdateBase {
    301         const int lockedBuffer;
    302         inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
    303         inline ssize_t operator()();
    304     };
    305 
    306     struct RetireUpdate : public UpdateBase {
    307         const int numBuffers;
    308         inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
    309         inline ssize_t operator()();
    310     };
    311 
    312     struct StatusUpdate : public UpdateBase {
    313         const status_t status;
    314         inline StatusUpdate(SharedBufferBase* sbb, status_t status);
    315         inline ssize_t operator()();
    316     };
    317 
    318     struct ReallocateCondition : public ConditionBase {
    319         int buf;
    320         inline ReallocateCondition(SharedBufferBase* sbb, int buf);
    321         inline bool operator()();
    322         static inline const char* name() { return "ReallocateCondition"; }
    323     };
    324 };
    325 
    326 // ===========================================================================
    327 
    328 struct display_cblk_t
    329 {
    330     uint16_t    w;
    331     uint16_t    h;
    332     uint8_t     format;
    333     uint8_t     orientation;
    334     uint8_t     reserved[2];
    335     float       fps;
    336     float       density;
    337     float       xdpi;
    338     float       ydpi;
    339     uint32_t    pad[2];
    340 };
    341 
    342 struct surface_flinger_cblk_t   // 4KB max
    343 {
    344     uint8_t         connected;
    345     uint8_t         reserved[3];
    346     uint32_t        pad[7];
    347     display_cblk_t  displays[NUM_DISPLAY_MAX];
    348 };
    349 
    350 // ---------------------------------------------------------------------------
    351 
    352 COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096)
    353 COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128)
    354 COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
    355 
    356 // ---------------------------------------------------------------------------
    357 }; // namespace android
    358 
    359 #endif /* ANDROID_SF_SHARED_BUFFER_STACK_H */
    360