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