summaryrefslogtreecommitdiffstats
path: root/libs/gui/SharedBufferStack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui/SharedBufferStack.cpp')
-rw-r--r--libs/gui/SharedBufferStack.cpp714
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