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