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