diff options
Diffstat (limited to 'libs/gui/SharedBufferStack.cpp')
-rw-r--r-- | libs/gui/SharedBufferStack.cpp | 714 |
1 files changed, 0 insertions, 714 deletions
diff --git a/libs/gui/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp deleted file mode 100644 index 7505d53..0000000 --- a/libs/gui/SharedBufferStack.cpp +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "SharedBufferStack" - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/threads.h> - -#include <private/surfaceflinger/SharedBufferStack.h> - -#include <ui/Rect.h> -#include <ui/Region.h> - -#define DEBUG_ATOMICS 0 - -namespace android { -// ---------------------------------------------------------------------------- - -SharedClient::SharedClient() - : lock(Mutex::SHARED), cv(Condition::SHARED) -{ -} - -SharedClient::~SharedClient() { -} - - -// these functions are used by the clients -status_t SharedClient::validate(size_t i) const { - if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX)) - return BAD_INDEX; - return surfaces[i].status; -} - -// ---------------------------------------------------------------------------- - - -SharedBufferStack::SharedBufferStack() -{ -} - -void SharedBufferStack::init(int32_t i) -{ - status = NO_ERROR; - identity = i; -} - -status_t SharedBufferStack::setCrop(int buffer, const Rect& crop) -{ - if (uint32_t(buffer) >= NUM_BUFFER_MAX) - return BAD_INDEX; - - buffers[buffer].crop.l = uint16_t(crop.left); - buffers[buffer].crop.t = uint16_t(crop.top); - buffers[buffer].crop.r = uint16_t(crop.right); - buffers[buffer].crop.b = uint16_t(crop.bottom); - return NO_ERROR; -} - -status_t SharedBufferStack::setTransform(int buffer, uint8_t transform) -{ - if (uint32_t(buffer) >= NUM_BUFFER_MAX) - return BAD_INDEX; - buffers[buffer].transform = transform; - return NO_ERROR; -} - -status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty) -{ - if (uint32_t(buffer) >= NUM_BUFFER_MAX) - return BAD_INDEX; - - FlatRegion& reg(buffers[buffer].dirtyRegion); - if (dirty.isEmpty()) { - reg.count = 0; - return NO_ERROR; - } - - size_t count; - Rect const* r = dirty.getArray(&count); - if (count > FlatRegion::NUM_RECT_MAX) { - const Rect bounds(dirty.getBounds()); - reg.count = 1; - reg.rects[0].l = uint16_t(bounds.left); - reg.rects[0].t = uint16_t(bounds.top); - reg.rects[0].r = uint16_t(bounds.right); - reg.rects[0].b = uint16_t(bounds.bottom); - } else { - reg.count = count; - for (size_t i=0 ; i<count ; i++) { - reg.rects[i].l = uint16_t(r[i].left); - reg.rects[i].t = uint16_t(r[i].top); - reg.rects[i].r = uint16_t(r[i].right); - reg.rects[i].b = uint16_t(r[i].bottom); - } - } - return NO_ERROR; -} - -Region SharedBufferStack::getDirtyRegion(int buffer) const -{ - Region res; - if (uint32_t(buffer) >= NUM_BUFFER_MAX) - return res; - - const FlatRegion& reg(buffers[buffer].dirtyRegion); - if (reg.count > FlatRegion::NUM_RECT_MAX) - return res; - - if (reg.count == 1) { - const Rect r( - reg.rects[0].l, - reg.rects[0].t, - reg.rects[0].r, - reg.rects[0].b); - res.set(r); - } else { - for (size_t i=0 ; i<reg.count ; i++) { - const Rect r( - reg.rects[i].l, - reg.rects[i].t, - reg.rects[i].r, - reg.rects[i].b); - res.orSelf(r); - } - } - return res; -} - -Rect SharedBufferStack::getCrop(int buffer) const -{ - Rect res(-1, -1); - if (uint32_t(buffer) >= NUM_BUFFER_MAX) - return res; - res.left = buffers[buffer].crop.l; - res.top = buffers[buffer].crop.t; - res.right = buffers[buffer].crop.r; - res.bottom = buffers[buffer].crop.b; - return res; -} - -uint32_t SharedBufferStack::getTransform(int buffer) const -{ - if (uint32_t(buffer) >= NUM_BUFFER_MAX) - return 0; - return buffers[buffer].transform; -} - - -// ---------------------------------------------------------------------------- - -SharedBufferBase::SharedBufferBase(SharedClient* sharedClient, - int surface, int32_t identity) - : mSharedClient(sharedClient), - mSharedStack(sharedClient->surfaces + surface), - mIdentity(identity) -{ -} - -SharedBufferBase::~SharedBufferBase() -{ -} - -status_t SharedBufferBase::getStatus() const -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.status; -} - -int32_t SharedBufferBase::getIdentity() const -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.identity; -} - -String8 SharedBufferBase::dump(char const* prefix) const -{ - const size_t SIZE = 1024; - char buffer[SIZE]; - String8 result; - SharedBufferStack& stack( *mSharedStack ); - snprintf(buffer, SIZE, - "%s[ head=%2d, available=%2d, queued=%2d ] " - "reallocMask=%08x, identity=%d, status=%d", - prefix, stack.head, stack.available, stack.queued, - stack.reallocMask, stack.identity, stack.status); - result.append(buffer); - result.append("\n"); - return result; -} - -status_t SharedBufferBase::waitForCondition(const ConditionBase& condition) -{ - const SharedBufferStack& stack( *mSharedStack ); - SharedClient& client( *mSharedClient ); - const nsecs_t TIMEOUT = s2ns(1); - const int identity = mIdentity; - - Mutex::Autolock _l(client.lock); - while ((condition()==false) && - (stack.identity == identity) && - (stack.status == NO_ERROR)) - { - status_t err = client.cv.waitRelative(client.lock, TIMEOUT); - // handle errors and timeouts - if (CC_UNLIKELY(err != NO_ERROR)) { - if (err == TIMED_OUT) { - if (condition()) { - LOGE("waitForCondition(%s) timed out (identity=%d), " - "but condition is true! We recovered but it " - "shouldn't happen." , condition.name(), stack.identity); - break; - } else { - LOGW("waitForCondition(%s) timed out " - "(identity=%d, status=%d). " - "CPU may be pegged. trying again.", condition.name(), - stack.identity, stack.status); - } - } else { - LOGE("waitForCondition(%s) error (%s) ", - condition.name(), strerror(-err)); - return err; - } - } - } - return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status; -} -// ============================================================================ -// conditions and updates -// ============================================================================ - -SharedBufferClient::DequeueCondition::DequeueCondition( - SharedBufferClient* sbc) : ConditionBase(sbc) { -} -bool SharedBufferClient::DequeueCondition::operator()() const { - return stack.available > 0; -} - -SharedBufferClient::LockCondition::LockCondition( - SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) { -} -bool SharedBufferClient::LockCondition::operator()() const { - // NOTE: if stack.head is messed up, we could crash the client - // or cause some drawing artifacts. This is okay, as long as it is - // limited to the client. - return (buf != stack.index[stack.head]); -} - -SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition( - SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs), - mNumBuffers(numBuffers) { -} -bool SharedBufferServer::BuffersAvailableCondition::operator()() const { - return stack.available == mNumBuffers; -} - -// ---------------------------------------------------------------------------- - -SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb) - : UpdateBase(sbb) { -} -ssize_t SharedBufferClient::QueueUpdate::operator()() { - android_atomic_inc(&stack.queued); - return NO_ERROR; -} - -SharedBufferClient::DequeueUpdate::DequeueUpdate(SharedBufferBase* sbb) - : UpdateBase(sbb) { -} -ssize_t SharedBufferClient::DequeueUpdate::operator()() { - if (android_atomic_dec(&stack.available) == 0) { - LOGW("dequeue probably called from multiple threads!"); - } - return NO_ERROR; -} - -SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb, - int tail, int buf) - : UpdateBase(sbb), tail(tail), buf(buf) { -} -ssize_t SharedBufferClient::CancelUpdate::operator()() { - stack.index[tail] = buf; - android_atomic_inc(&stack.available); - return NO_ERROR; -} - -SharedBufferServer::RetireUpdate::RetireUpdate( - SharedBufferBase* sbb, int numBuffers) - : UpdateBase(sbb), numBuffers(numBuffers) { -} -ssize_t SharedBufferServer::RetireUpdate::operator()() { - int32_t head = stack.head; - if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) - return BAD_VALUE; - - // Decrement the number of queued buffers - int32_t queued; - do { - queued = stack.queued; - if (queued == 0) { - return NOT_ENOUGH_DATA; - } - } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued)); - - // lock the buffer before advancing head, which automatically unlocks - // the buffer we preventively locked upon entering this function - - head = (head + 1) % numBuffers; - const int8_t headBuf = stack.index[head]; - stack.headBuf = headBuf; - - // head is only modified here, so we don't need to use cmpxchg - android_atomic_write(head, &stack.head); - - // now that head has moved, we can increment the number of available buffers - android_atomic_inc(&stack.available); - return head; -} - -SharedBufferServer::StatusUpdate::StatusUpdate( - SharedBufferBase* sbb, status_t status) - : UpdateBase(sbb), status(status) { -} - -ssize_t SharedBufferServer::StatusUpdate::operator()() { - android_atomic_write(status, &stack.status); - return NO_ERROR; -} - -// ============================================================================ - -SharedBufferClient::SharedBufferClient(SharedClient* sharedClient, - int surface, int num, int32_t identity) - : SharedBufferBase(sharedClient, surface, identity), - mNumBuffers(num), tail(0) -{ - SharedBufferStack& stack( *mSharedStack ); - tail = computeTail(); - queued_head = stack.head; -} - -int32_t SharedBufferClient::computeTail() const -{ - SharedBufferStack& stack( *mSharedStack ); - return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers; -} - -ssize_t SharedBufferClient::dequeue() -{ - SharedBufferStack& stack( *mSharedStack ); - - RWLock::AutoRLock _rd(mLock); - - const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD); - - //LOGD("[%d] about to dequeue a buffer", - // mSharedStack->identity); - DequeueCondition condition(this); - status_t err = waitForCondition(condition); - if (err != NO_ERROR) - return ssize_t(err); - - DequeueUpdate update(this); - updateCondition( update ); - - int dequeued = stack.index[tail]; - tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1); - LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s", - dequeued, tail, dump("").string()); - - mDequeueTime[dequeued] = dequeueTime; - - return dequeued; -} - -status_t SharedBufferClient::undoDequeue(int buf) -{ - return cancel(buf); -} - -status_t SharedBufferClient::cancel(int buf) -{ - RWLock::AutoRLock _rd(mLock); - - // calculate the new position of the tail index (essentially tail--) - int localTail = (tail + mNumBuffers - 1) % mNumBuffers; - CancelUpdate update(this, localTail, buf); - status_t err = updateCondition( update ); - if (err == NO_ERROR) { - tail = localTail; - } - return err; -} - -status_t SharedBufferClient::lock(int buf) -{ - RWLock::AutoRLock _rd(mLock); - - SharedBufferStack& stack( *mSharedStack ); - LockCondition condition(this, buf); - status_t err = waitForCondition(condition); - return err; -} - -status_t SharedBufferClient::queue(int buf) -{ - RWLock::AutoRLock _rd(mLock); - - SharedBufferStack& stack( *mSharedStack ); - - queued_head = (queued_head + 1) % mNumBuffers; - stack.index[queued_head] = buf; - - QueueUpdate update(this); - status_t err = updateCondition( update ); - LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string()); - - const nsecs_t now = systemTime(SYSTEM_TIME_THREAD); - stack.stats.totalTime = ns2us(now - mDequeueTime[buf]); - - return err; -} - -bool SharedBufferClient::needNewBuffer(int buf) const -{ - SharedBufferStack& stack( *mSharedStack ); - const uint32_t mask = 1<<(31-buf); - return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0; -} - -status_t SharedBufferClient::setCrop(int buf, const Rect& crop) -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.setCrop(buf, crop); -} - -status_t SharedBufferClient::setTransform(int buf, uint32_t transform) -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.setTransform(buf, uint8_t(transform)); -} - -status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg) -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.setDirtyRegion(buf, reg); -} - -status_t SharedBufferClient::setBufferCount( - int bufferCount, const SetBufferCountCallback& ipc) -{ - SharedBufferStack& stack( *mSharedStack ); - if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX) - return BAD_VALUE; - - if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN) - return BAD_VALUE; - - RWLock::AutoWLock _wr(mLock); - - status_t err = ipc(bufferCount); - if (err == NO_ERROR) { - mNumBuffers = bufferCount; - queued_head = (stack.head + stack.queued) % mNumBuffers; - tail = computeTail(); - } - return err; -} - -// ---------------------------------------------------------------------------- - -SharedBufferServer::SharedBufferServer(SharedClient* sharedClient, - int surface, int num, int32_t identity) - : SharedBufferBase(sharedClient, surface, identity), - mNumBuffers(num) -{ - mSharedStack->init(identity); - mSharedStack->token = surface; - mSharedStack->head = num-1; - mSharedStack->available = num; - mSharedStack->queued = 0; - mSharedStack->reallocMask = 0; - memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers)); - for (int i=0 ; i<num ; i++) { - mBufferList.add(i); - mSharedStack->index[i] = i; - } -} - -SharedBufferServer::~SharedBufferServer() -{ -} - -ssize_t SharedBufferServer::retireAndLock() -{ - RWLock::AutoRLock _l(mLock); - - RetireUpdate update(this, mNumBuffers); - ssize_t buf = updateCondition( update ); - if (buf >= 0) { - if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX) - return BAD_VALUE; - SharedBufferStack& stack( *mSharedStack ); - buf = stack.index[buf]; - LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", - int(buf), dump("").string()); - } - return buf; -} - -void SharedBufferServer::setStatus(status_t status) -{ - if (status < NO_ERROR) { - StatusUpdate update(this, status); - updateCondition( update ); - } -} - -status_t SharedBufferServer::reallocateAll() -{ - RWLock::AutoRLock _l(mLock); - - SharedBufferStack& stack( *mSharedStack ); - uint32_t mask = mBufferList.getMask(); - android_atomic_or(mask, &stack.reallocMask); - return NO_ERROR; -} - -status_t SharedBufferServer::reallocateAllExcept(int buffer) -{ - RWLock::AutoRLock _l(mLock); - - SharedBufferStack& stack( *mSharedStack ); - BufferList temp(mBufferList); - temp.remove(buffer); - uint32_t mask = temp.getMask(); - android_atomic_or(mask, &stack.reallocMask); - return NO_ERROR; -} - -int32_t SharedBufferServer::getQueuedCount() const -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.queued; -} - -Region SharedBufferServer::getDirtyRegion(int buf) const -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.getDirtyRegion(buf); -} - -Rect SharedBufferServer::getCrop(int buf) const -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.getCrop(buf); -} - -uint32_t SharedBufferServer::getTransform(int buf) const -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.getTransform(buf); -} - -/* - * NOTE: this is not thread-safe on the server-side, meaning - * 'head' cannot move during this operation. The client-side - * can safely operate an usual. - * - */ -status_t SharedBufferServer::resize(int newNumBuffers) -{ - if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN || - (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) { - return BAD_VALUE; - } - - RWLock::AutoWLock _l(mLock); - - if (newNumBuffers < mNumBuffers) { - return shrink(newNumBuffers); - } else { - return grow(newNumBuffers); - } -} - -status_t SharedBufferServer::grow(int newNumBuffers) -{ - SharedBufferStack& stack( *mSharedStack ); - const int numBuffers = mNumBuffers; - const int extra = newNumBuffers - numBuffers; - - // read the head, make sure it's valid - int32_t head = stack.head; - if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) - return BAD_VALUE; - - int base = numBuffers; - int32_t avail = stack.available; - int tail = head - avail + 1; - - if (tail >= 0) { - int8_t* const index = const_cast<int8_t*>(stack.index); - const int nb = numBuffers - head; - memmove(&index[head + extra], &index[head], nb); - base = head; - // move head 'extra' ahead, this doesn't impact stack.index[head]; - stack.head = head + extra; - } - stack.available += extra; - - // fill the new free space with unused buffers - BufferList::const_iterator curr(mBufferList.free_begin()); - for (int i=0 ; i<extra ; i++) { - stack.index[base+i] = *curr; - mBufferList.add(*curr); - ++curr; - } - - mNumBuffers = newNumBuffers; - return NO_ERROR; -} - -status_t SharedBufferServer::shrink(int newNumBuffers) -{ - SharedBufferStack& stack( *mSharedStack ); - - // Shrinking is only supported if there are no buffers currently dequeued. - int32_t avail = stack.available; - int32_t queued = stack.queued; - if (avail + queued != mNumBuffers) { - return INVALID_OPERATION; - } - - // Wait for any queued buffers to be displayed. - BuffersAvailableCondition condition(this, mNumBuffers); - status_t err = waitForCondition(condition); - if (err < 0) { - return err; - } - - // Reset head to index 0 and make it refer to buffer 0. The same renaming - // (head -> 0) is done in the BufferManager. - int32_t head = stack.head; - int8_t* index = const_cast<int8_t*>(stack.index); - for (int8_t i = 0; i < newNumBuffers; i++) { - index[i] = i; - } - stack.head = 0; - stack.headBuf = 0; - - // Free the buffers from the end of the list that are no longer needed. - for (int i = newNumBuffers; i < mNumBuffers; i++) { - mBufferList.remove(i); - } - - // Tell the client to reallocate all the buffers. - reallocateAll(); - - mNumBuffers = newNumBuffers; - stack.available = newNumBuffers; - - return NO_ERROR; -} - -SharedBufferStack::Statistics SharedBufferServer::getStats() const -{ - SharedBufferStack& stack( *mSharedStack ); - return stack.stats; -} - -// --------------------------------------------------------------------------- -status_t SharedBufferServer::BufferList::add(int value) -{ - if (uint32_t(value) >= mCapacity) - return BAD_VALUE; - uint32_t mask = 1<<(31-value); - if (mList & mask) - return ALREADY_EXISTS; - mList |= mask; - return NO_ERROR; -} - -status_t SharedBufferServer::BufferList::remove(int value) -{ - if (uint32_t(value) >= mCapacity) - return BAD_VALUE; - uint32_t mask = 1<<(31-value); - if (!(mList & mask)) - return NAME_NOT_FOUND; - mList &= ~mask; - return NO_ERROR; -} - - -// --------------------------------------------------------------------------- -}; // namespace android |