ConsumerBase.cpp 8.59 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (C) 2010 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.
 */

Mark Salyzyn's avatar
Mark Salyzyn committed
17 18
#include <inttypes.h>

19 20 21 22 23 24 25 26 27 28 29
#define LOG_TAG "ConsumerBase"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0

#define EGL_EGLEXT_PROTOTYPES

#include <EGL/egl.h>
#include <EGL/eglext.h>

#include <hardware/hardware.h>

30
#include <gui/BufferItem.h>
31 32 33 34 35 36 37 38 39 40 41 42
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/ConsumerBase.h>

#include <private/gui/ComposerService.h>

#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/Trace.h>

// Macros for including the ConsumerBase name in log messages
43
#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
44 45 46
//#define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
//#define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
//#define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
47
#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
48 49 50 51 52 53 54 55 56

namespace android {

// Get an ID that's unique within this process.
static int32_t createProcessUniqueId() {
    static volatile int32_t globalCounter = 0;
    return android_atomic_inc(&globalCounter);
}

57
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
58
        mAbandoned(false),
59
        mConsumer(bufferQueue) {
60 61 62 63 64 65 66
    // Choose a name using the PID and a process-unique ID.
    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());

    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
    // reference once the ctor ends, as that would cause the refcount of 'this'
    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
    // that's what we create.
67 68
    wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
    sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
69

70
    status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
71
    if (err != NO_ERROR) {
72
        CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
73 74
                strerror(-err), err);
    } else {
75
        mConsumer->setConsumerName(mName);
76 77 78 79
    }
}

ConsumerBase::~ConsumerBase() {
Jamie Gennis's avatar
Jamie Gennis committed
80 81 82 83 84 85 86 87 88 89 90
    CB_LOGV("~ConsumerBase");
    Mutex::Autolock lock(mMutex);

    // Verify that abandon() has been called before we get here.  This should
    // be done by ConsumerBase::onLastStrongRef(), but it's possible for a
    // derived class to override that method and not call
    // ConsumerBase::onLastStrongRef().
    LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the "
        "consumer is not abandoned!", mName.string());
}

91
void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) {
92 93 94 95 96 97
    abandon();
}

void ConsumerBase::freeBufferLocked(int slotIndex) {
    CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
    mSlots[slotIndex].mGraphicBuffer = 0;
98
    mSlots[slotIndex].mFence = Fence::NO_FENCE;
99
    mSlots[slotIndex].mFrameNumber = 0;
100 101
}

102
void ConsumerBase::onFrameAvailable(const BufferItem& item) {
103 104 105 106 107
    CB_LOGV("onFrameAvailable");

    sp<FrameAvailableListener> listener;
    { // scope for the lock
        Mutex::Autolock lock(mMutex);
108
        listener = mFrameAvailableListener.promote();
109 110 111 112
    }

    if (listener != NULL) {
        CB_LOGV("actually calling onFrameAvailable");
113
        listener->onFrameAvailable(item);
114 115 116 117
    }
}

void ConsumerBase::onBuffersReleased() {
118
    Mutex::Autolock lock(mMutex);
119

120
    CB_LOGV("onBuffersReleased");
121

122 123 124
    if (mAbandoned) {
        // Nothing to do if we're already abandoned.
        return;
125 126
    }

127
    uint64_t mask = 0;
128
    mConsumer->getReleasedBuffers(&mask);
129
    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
130
        if (mask & (1ULL << i)) {
131 132
            freeBufferLocked(i);
        }
133 134 135
    }
}

136 137 138
void ConsumerBase::onSidebandStreamChanged() {
}

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
void ConsumerBase::abandon() {
    CB_LOGV("abandon");
    Mutex::Autolock lock(mMutex);

    if (!mAbandoned) {
        abandonLocked();
        mAbandoned = true;
    }
}

void ConsumerBase::abandonLocked() {
	CB_LOGV("abandonLocked");
    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
        freeBufferLocked(i);
    }
    // disconnect from the BufferQueue
155 156
    mConsumer->consumerDisconnect();
    mConsumer.clear();
157 158 159
}

void ConsumerBase::setFrameAvailableListener(
160
        const wp<FrameAvailableListener>& listener) {
161 162 163 164 165
    CB_LOGV("setFrameAvailableListener");
    Mutex::Autolock lock(mMutex);
    mFrameAvailableListener = listener;
}

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
status_t ConsumerBase::detachBuffer(int slot) {
    CB_LOGV("detachBuffer");
    Mutex::Autolock lock(mMutex);

    status_t result = mConsumer->detachBuffer(slot);
    if (result != NO_ERROR) {
        CB_LOGE("Failed to detach buffer: %d", result);
        return result;
    }

    freeBufferLocked(slot);

    return result;
}

181
void ConsumerBase::dump(String8& result) const {
182
    dump(result, "");
183 184
}

185
void ConsumerBase::dump(String8& result, const char* prefix) const {
186
    Mutex::Autolock _l(mMutex);
187
    dumpLocked(result, prefix);
188 189
}

190 191
void ConsumerBase::dumpLocked(String8& result, const char* prefix) const {
    result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned));
192 193

    if (!mAbandoned) {
194
        mConsumer->dump(result, prefix);
195 196 197
    }
}

198
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
199
        nsecs_t presentWhen) {
200
    status_t err = mConsumer->acquireBuffer(item, presentWhen);
201 202 203 204 205 206 207 208
    if (err != NO_ERROR) {
        return err;
    }

    if (item->mGraphicBuffer != NULL) {
        mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
    }

209
    mSlots[item->mBuf].mFrameNumber = item->mFrameNumber;
210 211
    mSlots[item->mBuf].mFence = item->mFence;

Mark Salyzyn's avatar
Mark Salyzyn committed
212
    CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
213
            item->mBuf, item->mFrameNumber);
214 215 216 217

    return OK;
}

218 219
status_t ConsumerBase::addReleaseFence(int slot,
        const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
220
    Mutex::Autolock lock(mMutex);
221
    return addReleaseFenceLocked(slot, graphicBuffer, fence);
222 223
}

224 225
status_t ConsumerBase::addReleaseFenceLocked(int slot,
        const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) {
226
    CB_LOGV("addReleaseFenceLocked: slot=%d", slot);
227

228 229 230 231 232 233
    // If consumer no longer tracks this graphicBuffer, we can safely
    // drop this fence, as it will never be received by the producer.
    if (!stillTracking(slot, graphicBuffer)) {
        return OK;
    }

234 235 236 237
    if (!mSlots[slot].mFence.get()) {
        mSlots[slot].mFence = fence;
    } else {
        sp<Fence> mergedFence = Fence::merge(
238
                String8::format("%.28s:%d", mName.string(), slot),
239 240 241 242 243 244 245 246 247 248 249 250 251 252
                mSlots[slot].mFence, fence);
        if (!mergedFence.get()) {
            CB_LOGE("failed to merge release fences");
            // synchronization is broken, the best we can do is hope fences
            // signal in order so the new fence will act like a union
            mSlots[slot].mFence = fence;
            return BAD_VALUE;
        }
        mSlots[slot].mFence = mergedFence;
    }

    return OK;
}

253 254 255 256 257 258 259 260 261 262
status_t ConsumerBase::releaseBufferLocked(
        int slot, const sp<GraphicBuffer> graphicBuffer,
        EGLDisplay display, EGLSyncKHR eglFence) {
    // If consumer no longer tracks this graphicBuffer (we received a new
    // buffer on the same slot), the buffer producer is definitely no longer
    // tracking it.
    if (!stillTracking(slot, graphicBuffer)) {
        return OK;
    }

Mark Salyzyn's avatar
Mark Salyzyn committed
263
    CB_LOGV("releaseBufferLocked: slot=%d/%" PRIu64,
264
            slot, mSlots[slot].mFrameNumber);
265
    status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber,
266
            display, eglFence, mSlots[slot].mFence);
267
    if (err == IGraphicBufferConsumer::STALE_BUFFER_SLOT) {
268 269 270
        freeBufferLocked(slot);
    }

271
    mSlots[slot].mFence = Fence::NO_FENCE;
272 273 274 275

    return err;
}

276 277 278 279 280 281 282 283 284
bool ConsumerBase::stillTracking(int slot,
        const sp<GraphicBuffer> graphicBuffer) {
    if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
        return false;
    }
    return (mSlots[slot].mGraphicBuffer != NULL &&
            mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
}

285
} // namespace android