| /* |
| * Copyright (C) 2012 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_NDEBUG 0 |
| #define LOG_TAG "CpuConsumer" |
| //#define ATRACE_TAG ATRACE_TAG_GRAPHICS |
| |
| #include <gui/CpuConsumer.h> |
| |
| #include <gui/BufferItem.h> |
| #include <utils/Log.h> |
| |
| #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) |
| // #define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) |
| // #define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) |
| #define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) |
| #define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) |
| |
| namespace android { |
| |
| CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, |
| size_t maxLockedBuffers, bool controlledByApp) : |
| ConsumerBase(bq, controlledByApp), |
| mMaxLockedBuffers(maxLockedBuffers), |
| mCurrentLockedBuffers(0) |
| { |
| // Create tracking entries for locked buffers |
| mAcquiredBuffers.insertAt(0, maxLockedBuffers); |
| |
| mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); |
| mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers)); |
| } |
| |
| size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const { |
| for (size_t i = 0; i < mMaxLockedBuffers; i++) { |
| const auto& ab = mAcquiredBuffers[i]; |
| // note that this finds AcquiredBuffer::kUnusedId as well |
| if (ab.mLockedBufferId == id) { |
| return i; |
| } |
| } |
| return mMaxLockedBuffers; // an invalid index |
| } |
| |
| static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) { |
| return reinterpret_cast<uintptr_t>(buffer.data); |
| } |
| |
| static bool isPossiblyYUV(PixelFormat format) { |
| switch (static_cast<int>(format)) { |
| case HAL_PIXEL_FORMAT_RGBA_8888: |
| case HAL_PIXEL_FORMAT_RGBX_8888: |
| case HAL_PIXEL_FORMAT_RGBA_FP16: |
| case HAL_PIXEL_FORMAT_RGBA_1010102: |
| case HAL_PIXEL_FORMAT_RGB_888: |
| case HAL_PIXEL_FORMAT_RGB_565: |
| case HAL_PIXEL_FORMAT_BGRA_8888: |
| case HAL_PIXEL_FORMAT_Y8: |
| case HAL_PIXEL_FORMAT_Y16: |
| case HAL_PIXEL_FORMAT_RAW16: |
| case HAL_PIXEL_FORMAT_RAW12: |
| case HAL_PIXEL_FORMAT_RAW10: |
| case HAL_PIXEL_FORMAT_RAW_OPAQUE: |
| case HAL_PIXEL_FORMAT_BLOB: |
| case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: |
| return false; |
| |
| case HAL_PIXEL_FORMAT_YV12: |
| case HAL_PIXEL_FORMAT_YCbCr_420_888: |
| case HAL_PIXEL_FORMAT_YCbCr_422_SP: |
| case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
| case HAL_PIXEL_FORMAT_YCbCr_422_I: |
| default: |
| return true; |
| } |
| } |
| |
| status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const { |
| android_ycbcr ycbcr = android_ycbcr(); |
| |
| PixelFormat format = item.mGraphicBuffer->getPixelFormat(); |
| PixelFormat flexFormat = format; |
| if (isPossiblyYUV(format)) { |
| int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; |
| status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN, |
| item.mCrop, &ycbcr, fenceFd); |
| if (err == OK) { |
| flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; |
| if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { |
| CC_LOGV("locking buffer of format %#x as flex YUV", format); |
| } |
| } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { |
| CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err); |
| return err; |
| } |
| } |
| |
| if (ycbcr.y != nullptr) { |
| outBuffer->data = reinterpret_cast<uint8_t*>(ycbcr.y); |
| outBuffer->stride = static_cast<uint32_t>(ycbcr.ystride); |
| outBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); |
| outBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); |
| outBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); |
| outBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); |
| } else { |
| // not flexible YUV; try lockAsync |
| void* bufferPointer = nullptr; |
| int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; |
| status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN, |
| item.mCrop, &bufferPointer, fenceFd); |
| if (err != OK) { |
| CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err); |
| return err; |
| } |
| |
| outBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer); |
| outBuffer->stride = item.mGraphicBuffer->getStride(); |
| outBuffer->dataCb = nullptr; |
| outBuffer->dataCr = nullptr; |
| outBuffer->chromaStride = 0; |
| outBuffer->chromaStep = 0; |
| } |
| |
| outBuffer->width = item.mGraphicBuffer->getWidth(); |
| outBuffer->height = item.mGraphicBuffer->getHeight(); |
| outBuffer->format = format; |
| outBuffer->flexFormat = flexFormat; |
| |
| outBuffer->crop = item.mCrop; |
| outBuffer->transform = item.mTransform; |
| outBuffer->scalingMode = item.mScalingMode; |
| outBuffer->timestamp = item.mTimestamp; |
| outBuffer->dataSpace = item.mDataSpace; |
| outBuffer->frameNumber = item.mFrameNumber; |
| |
| return OK; |
| } |
| |
| status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { |
| status_t err; |
| |
| if (!nativeBuffer) return BAD_VALUE; |
| |
| Mutex::Autolock _l(mMutex); |
| |
| if (mCurrentLockedBuffers == mMaxLockedBuffers) { |
| CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", |
| mMaxLockedBuffers); |
| return NOT_ENOUGH_DATA; |
| } |
| |
| BufferItem b; |
| err = acquireBufferLocked(&b, 0); |
| if (err != OK) { |
| if (err == BufferQueue::NO_BUFFER_AVAILABLE) { |
| return BAD_VALUE; |
| } else { |
| CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); |
| return err; |
| } |
| } |
| |
| if (b.mGraphicBuffer == nullptr) { |
| b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer; |
| } |
| |
| err = lockBufferItem(b, nativeBuffer); |
| if (err != OK) { |
| return err; |
| } |
| |
| // find an unused AcquiredBuffer |
| size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId); |
| ALOG_ASSERT(lockedIdx < mMaxLockedBuffers); |
| AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); |
| |
| ab.mSlot = b.mSlot; |
| ab.mGraphicBuffer = b.mGraphicBuffer; |
| ab.mLockedBufferId = getLockedBufferId(*nativeBuffer); |
| |
| mCurrentLockedBuffers++; |
| |
| return OK; |
| } |
| |
| status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { |
| Mutex::Autolock _l(mMutex); |
| |
| uintptr_t id = getLockedBufferId(nativeBuffer); |
| size_t lockedIdx = |
| (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers; |
| if (lockedIdx == mMaxLockedBuffers) { |
| CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| |
| AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); |
| |
| int fenceFd = -1; |
| status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd); |
| if (err != OK) { |
| CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, |
| lockedIdx); |
| return err; |
| } |
| |
| sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); |
| addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence); |
| releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer); |
| |
| ab.reset(); |
| |
| mCurrentLockedBuffers--; |
| |
| return OK; |
| } |
| |
| } // namespace android |