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