1 /* 2 * Copyright (C) 2013 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 #define LOG_TAG "Camera3-IOStreamBase" 18 #define ATRACE_TAG ATRACE_TAG_CAMERA 19 //#define LOG_NDEBUG 0 20 21 #include <inttypes.h> 22 23 #include <utils/Log.h> 24 #include <utils/Trace.h> 25 #include "device3/Camera3IOStreamBase.h" 26 #include "device3/StatusTracker.h" 27 28 namespace android { 29 30 namespace camera3 { 31 32 Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type, 33 uint32_t width, uint32_t height, size_t maxSize, int format, 34 android_dataspace dataSpace, camera3_stream_rotation_t rotation, int setId) : 35 Camera3Stream(id, type, 36 width, height, maxSize, format, dataSpace, rotation, setId), 37 mTotalBufferCount(0), 38 mHandoutTotalBufferCount(0), 39 mHandoutOutputBufferCount(0), 40 mFrameCount(0), 41 mLastTimestamp(0) { 42 43 mCombinedFence = new Fence(); 44 45 if (maxSize > 0 && 46 (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE)) { 47 ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__, 48 format); 49 mState = STATE_ERROR; 50 } 51 } 52 53 Camera3IOStreamBase::~Camera3IOStreamBase() { 54 disconnectLocked(); 55 } 56 57 bool Camera3IOStreamBase::hasOutstandingBuffersLocked() const { 58 nsecs_t signalTime = mCombinedFence->getSignalTime(); 59 ALOGV("%s: Stream %d: Has %zu outstanding buffers," 60 " buffer signal time is %" PRId64, 61 __FUNCTION__, mId, mHandoutTotalBufferCount, signalTime); 62 if (mHandoutTotalBufferCount > 0 || signalTime == INT64_MAX) { 63 return true; 64 } 65 return false; 66 } 67 68 void Camera3IOStreamBase::dump(int fd, const Vector<String16> &args) const { 69 (void) args; 70 String8 lines; 71 72 uint32_t consumerUsage = 0; 73 status_t res = getEndpointUsage(&consumerUsage); 74 if (res != OK) consumerUsage = 0; 75 76 lines.appendFormat(" State: %d\n", mState); 77 lines.appendFormat(" Dims: %d x %d, format 0x%x, dataspace 0x%x\n", 78 camera3_stream::width, camera3_stream::height, 79 camera3_stream::format, camera3_stream::data_space); 80 lines.appendFormat(" Max size: %zu\n", mMaxSize); 81 lines.appendFormat(" Combined usage: %d, max HAL buffers: %d\n", 82 camera3_stream::usage | consumerUsage, camera3_stream::max_buffers); 83 lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n", 84 mFrameCount, mLastTimestamp); 85 lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n", 86 mTotalBufferCount, mHandoutTotalBufferCount); 87 write(fd, lines.string(), lines.size()); 88 89 Camera3Stream::dump(fd, args); 90 } 91 92 status_t Camera3IOStreamBase::configureQueueLocked() { 93 status_t res; 94 95 switch (mState) { 96 case STATE_IN_RECONFIG: 97 res = disconnectLocked(); 98 if (res != OK) { 99 return res; 100 } 101 break; 102 case STATE_IN_CONFIG: 103 // OK 104 break; 105 default: 106 ALOGE("%s: Bad state: %d", __FUNCTION__, mState); 107 return INVALID_OPERATION; 108 } 109 110 return OK; 111 } 112 113 size_t Camera3IOStreamBase::getBufferCountLocked() { 114 return mTotalBufferCount; 115 } 116 117 size_t Camera3IOStreamBase::getHandoutOutputBufferCountLocked() { 118 return mHandoutOutputBufferCount; 119 } 120 121 size_t Camera3IOStreamBase::getHandoutInputBufferCountLocked() { 122 return (mHandoutTotalBufferCount - mHandoutOutputBufferCount); 123 } 124 125 status_t Camera3IOStreamBase::disconnectLocked() { 126 switch (mState) { 127 case STATE_IN_RECONFIG: 128 case STATE_CONFIGURED: 129 case STATE_ABANDONED: 130 // OK 131 break; 132 default: 133 // No connection, nothing to do 134 ALOGV("%s: Stream %d: Already disconnected", 135 __FUNCTION__, mId); 136 return -ENOTCONN; 137 } 138 139 if (mHandoutTotalBufferCount > 0) { 140 ALOGE("%s: Can't disconnect with %zu buffers still dequeued!", 141 __FUNCTION__, mHandoutTotalBufferCount); 142 return INVALID_OPERATION; 143 } 144 145 return OK; 146 } 147 148 void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, 149 buffer_handle_t *handle, 150 int acquireFence, 151 int releaseFence, 152 camera3_buffer_status_t status, 153 bool output) { 154 /** 155 * Note that all fences are now owned by HAL. 156 */ 157 158 // Handing out a raw pointer to this object. Increment internal refcount. 159 incStrong(this); 160 buffer.stream = this; 161 buffer.buffer = handle; 162 buffer.acquire_fence = acquireFence; 163 buffer.release_fence = releaseFence; 164 buffer.status = status; 165 166 // Inform tracker about becoming busy 167 if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG && 168 mState != STATE_IN_RECONFIG && mState != STATE_PREPARING) { 169 /** 170 * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers 171 * before/after register_stream_buffers during initial configuration 172 * or re-configuration, or during prepare pre-allocation 173 */ 174 sp<StatusTracker> statusTracker = mStatusTracker.promote(); 175 if (statusTracker != 0) { 176 statusTracker->markComponentActive(mStatusId); 177 } 178 } 179 mHandoutTotalBufferCount++; 180 181 if (output) { 182 mHandoutOutputBufferCount++; 183 } 184 } 185 186 status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const { 187 // Allow dequeue during IN_[RE]CONFIG for registration, in 188 // PREPARING for pre-allocation 189 if (mState != STATE_CONFIGURED && 190 mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG && 191 mState != STATE_PREPARING) { 192 ALOGE("%s: Stream %d: Can't get buffers in unconfigured state %d", 193 __FUNCTION__, mId, mState); 194 return INVALID_OPERATION; 195 } 196 197 return OK; 198 } 199 200 status_t Camera3IOStreamBase::returnBufferPreconditionCheckLocked() const { 201 // Allow buffers to be returned in the error state, to allow for disconnect 202 // and in the in-config states for registration 203 if (mState == STATE_CONSTRUCTED) { 204 ALOGE("%s: Stream %d: Can't return buffers in unconfigured state %d", 205 __FUNCTION__, mId, mState); 206 return INVALID_OPERATION; 207 } 208 if (mHandoutTotalBufferCount == 0) { 209 ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__, 210 mId); 211 return INVALID_OPERATION; 212 } 213 214 return OK; 215 } 216 217 status_t Camera3IOStreamBase::returnAnyBufferLocked( 218 const camera3_stream_buffer &buffer, 219 nsecs_t timestamp, 220 bool output) { 221 status_t res; 222 223 // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be 224 // decrementing the internal refcount next. In case this is the last ref, we 225 // might get destructed on the decStrong(), so keep an sp around until the 226 // end of the call - otherwise have to sprinkle the decStrong on all exit 227 // points. 228 sp<Camera3IOStreamBase> keepAlive(this); 229 decStrong(this); 230 231 if ((res = returnBufferPreconditionCheckLocked()) != OK) { 232 return res; 233 } 234 235 sp<Fence> releaseFence; 236 res = returnBufferCheckedLocked(buffer, timestamp, output, 237 &releaseFence); 238 // Res may be an error, but we still want to decrement our owned count 239 // to enable clean shutdown. So we'll just return the error but otherwise 240 // carry on 241 242 if (releaseFence != 0) { 243 mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); 244 } 245 246 if (output) { 247 mHandoutOutputBufferCount--; 248 } 249 250 mHandoutTotalBufferCount--; 251 if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG && 252 mState != STATE_IN_RECONFIG && mState != STATE_PREPARING) { 253 /** 254 * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers 255 * before/after register_stream_buffers during initial configuration 256 * or re-configuration, or during prepare pre-allocation 257 */ 258 ALOGV("%s: Stream %d: All buffers returned; now idle", __FUNCTION__, 259 mId); 260 sp<StatusTracker> statusTracker = mStatusTracker.promote(); 261 if (statusTracker != 0) { 262 statusTracker->markComponentIdle(mStatusId, mCombinedFence); 263 } 264 } 265 266 mBufferReturnedSignal.signal(); 267 268 if (output) { 269 mLastTimestamp = timestamp; 270 } 271 272 return res; 273 } 274 275 276 277 }; // namespace camera3 278 279 }; // namespace android 280