1 /*
2 * Copyright (C) 2019 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-BufUtils"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 //#define LOG_NDEBUG 0
20 //#define LOG_NNDEBUG 0 // Per-frame verbose logging
21
22 #include <inttypes.h>
23
24 #include <utils/Log.h>
25
26 #include "device3/BufferUtils.h"
27
28 namespace android {
29 namespace camera3 {
30
mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status)31 camera_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
32 using hardware::camera::device::V3_2::BufferStatus;
33
34 switch (status) {
35 case BufferStatus::OK: return CAMERA_BUFFER_STATUS_OK;
36 case BufferStatus::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
37 }
38 return CAMERA_BUFFER_STATUS_ERROR;
39 }
40
takeInflightBufferMap(BufferRecords & other)41 void BufferRecords::takeInflightBufferMap(BufferRecords& other) {
42 std::lock_guard<std::mutex> oLock(other.mInflightLock);
43 std::lock_guard<std::mutex> lock(mInflightLock);
44 if (mInflightBufferMap.size() > 0) {
45 ALOGE("%s: inflight map is set in non-empty state!", __FUNCTION__);
46 }
47 mInflightBufferMap = std::move(other.mInflightBufferMap);
48 other.mInflightBufferMap.clear();
49 }
50
takeRequestedBufferMap(BufferRecords & other)51 void BufferRecords::takeRequestedBufferMap(BufferRecords& other) {
52 std::lock_guard<std::mutex> oLock(other.mRequestedBuffersLock);
53 std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
54 if (mRequestedBufferMap.size() > 0) {
55 ALOGE("%s: requested buffer map is set in non-empty state!", __FUNCTION__);
56 }
57 mRequestedBufferMap = std::move(other.mRequestedBufferMap);
58 other.mRequestedBufferMap.clear();
59 }
60
takeBufferCaches(BufferRecords & other,const std::vector<int32_t> & streams)61 void BufferRecords::takeBufferCaches(BufferRecords& other, const std::vector<int32_t>& streams) {
62 std::lock_guard<std::mutex> oLock(other.mBufferIdMapLock);
63 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
64 if (mBufferIdMaps.size() > 0) {
65 ALOGE("%s: buffer ID map is set in non-empty state!", __FUNCTION__);
66 }
67 for (auto streamId : streams) {
68 mBufferIdMaps.insert({streamId, std::move(other.mBufferIdMaps.at(streamId))});
69 }
70 other.mBufferIdMaps.clear();
71 }
72
getBufferId(const buffer_handle_t & buf,int streamId)73 std::pair<bool, uint64_t> BufferRecords::getBufferId(
74 const buffer_handle_t& buf, int streamId) {
75 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
76
77 BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
78 auto it = bIdMap.find(buf);
79 if (it == bIdMap.end()) {
80 bIdMap[buf] = mNextBufferId++;
81 ALOGV("stream %d now have %zu buffer caches, buf %p",
82 streamId, bIdMap.size(), buf);
83 return std::make_pair(true, mNextBufferId - 1);
84 } else {
85 return std::make_pair(false, it->second);
86 }
87 }
88
tryCreateBufferCache(int streamId)89 void BufferRecords::tryCreateBufferCache(int streamId) {
90 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
91 if (mBufferIdMaps.count(streamId) == 0) {
92 mBufferIdMaps.emplace(streamId, BufferIdMap{});
93 }
94 }
95
removeInactiveBufferCaches(const std::set<int32_t> & activeStreams)96 void BufferRecords::removeInactiveBufferCaches(const std::set<int32_t>& activeStreams) {
97 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
98 for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) {
99 int streamId = it->first;
100 bool active = activeStreams.count(streamId) > 0;
101 if (!active) {
102 it = mBufferIdMaps.erase(it);
103 } else {
104 ++it;
105 }
106 }
107 }
108
removeOneBufferCache(int streamId,const native_handle_t * handle)109 uint64_t BufferRecords::removeOneBufferCache(int streamId, const native_handle_t* handle) {
110 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
111 uint64_t bufferId = BUFFER_ID_NO_BUFFER;
112 auto mapIt = mBufferIdMaps.find(streamId);
113 if (mapIt == mBufferIdMaps.end()) {
114 // streamId might be from a deleted stream here
115 ALOGI("%s: stream %d has been removed",
116 __FUNCTION__, streamId);
117 return BUFFER_ID_NO_BUFFER;
118 }
119 BufferIdMap& bIdMap = mapIt->second;
120 auto it = bIdMap.find(handle);
121 if (it == bIdMap.end()) {
122 ALOGW("%s: cannot find buffer %p in stream %d",
123 __FUNCTION__, handle, streamId);
124 return BUFFER_ID_NO_BUFFER;
125 } else {
126 bufferId = it->second;
127 bIdMap.erase(it);
128 ALOGV("%s: stream %d now have %zu buffer caches after removing buf %p",
129 __FUNCTION__, streamId, bIdMap.size(), handle);
130 }
131 return bufferId;
132 }
133
clearBufferCaches(int streamId)134 std::vector<uint64_t> BufferRecords::clearBufferCaches(int streamId) {
135 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
136 std::vector<uint64_t> ret;
137 auto mapIt = mBufferIdMaps.find(streamId);
138 if (mapIt == mBufferIdMaps.end()) {
139 ALOGE("%s: streamId %d not found!", __FUNCTION__, streamId);
140 return ret;
141 }
142 BufferIdMap& bIdMap = mapIt->second;
143 ret.reserve(bIdMap.size());
144 for (const auto& it : bIdMap) {
145 ret.push_back(it.second);
146 }
147 bIdMap.clear();
148 return ret;
149 }
150
isStreamCached(int streamId)151 bool BufferRecords::isStreamCached(int streamId) {
152 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
153 return mBufferIdMaps.find(streamId) != mBufferIdMaps.end();
154 }
155
verifyBufferIds(int32_t streamId,std::vector<uint64_t> & bufIds)156 bool BufferRecords::verifyBufferIds(
157 int32_t streamId, std::vector<uint64_t>& bufIds) {
158 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
159 camera3::BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
160 if (bIdMap.size() != bufIds.size()) {
161 ALOGE("%s: stream ID %d buffer cache number mismatch: %zu/%zu (service/HAL)",
162 __FUNCTION__, streamId, bIdMap.size(), bufIds.size());
163 return false;
164 }
165 std::vector<uint64_t> internalBufIds;
166 internalBufIds.reserve(bIdMap.size());
167 for (const auto& pair : bIdMap) {
168 internalBufIds.push_back(pair.second);
169 }
170 std::sort(bufIds.begin(), bufIds.end());
171 std::sort(internalBufIds.begin(), internalBufIds.end());
172 for (size_t i = 0; i < bufIds.size(); i++) {
173 if (bufIds[i] != internalBufIds[i]) {
174 ALOGE("%s: buffer cache mismatch! Service %" PRIu64 ", HAL %" PRIu64,
175 __FUNCTION__, internalBufIds[i], bufIds[i]);
176 return false;
177 }
178 }
179 return true;
180 }
181
getInflightBufferKeys(std::vector<std::pair<int32_t,int32_t>> * out)182 void BufferRecords::getInflightBufferKeys(
183 std::vector<std::pair<int32_t, int32_t>>* out) {
184 std::lock_guard<std::mutex> lock(mInflightLock);
185 out->clear();
186 out->reserve(mInflightBufferMap.size());
187 for (auto& pair : mInflightBufferMap) {
188 uint64_t key = pair.first;
189 int32_t streamId = key & 0xFFFFFFFF;
190 int32_t frameNumber = (key >> 32) & 0xFFFFFFFF;
191 out->push_back(std::make_pair(frameNumber, streamId));
192 }
193 return;
194 }
195
pushInflightBuffer(int32_t frameNumber,int32_t streamId,buffer_handle_t * buffer)196 status_t BufferRecords::pushInflightBuffer(
197 int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) {
198 std::lock_guard<std::mutex> lock(mInflightLock);
199 uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
200 mInflightBufferMap[key] = buffer;
201 return OK;
202 }
203
popInflightBuffer(int32_t frameNumber,int32_t streamId,buffer_handle_t ** buffer)204 status_t BufferRecords::popInflightBuffer(
205 int32_t frameNumber, int32_t streamId,
206 /*out*/ buffer_handle_t **buffer) {
207 std::lock_guard<std::mutex> lock(mInflightLock);
208
209 uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
210 auto it = mInflightBufferMap.find(key);
211 if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND;
212 if (buffer != nullptr) {
213 *buffer = it->second;
214 }
215 mInflightBufferMap.erase(it);
216 return OK;
217 }
218
popInflightBuffers(const std::vector<std::pair<int32_t,int32_t>> & buffers)219 void BufferRecords::popInflightBuffers(
220 const std::vector<std::pair<int32_t, int32_t>>& buffers) {
221 for (const auto& pair : buffers) {
222 int32_t frameNumber = pair.first;
223 int32_t streamId = pair.second;
224 popInflightBuffer(frameNumber, streamId, nullptr);
225 }
226 }
227
pushInflightRequestBuffer(uint64_t bufferId,buffer_handle_t * buf,int32_t streamId)228 status_t BufferRecords::pushInflightRequestBuffer(
229 uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) {
230 std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
231 auto pair = mRequestedBufferMap.insert({bufferId, {streamId, buf}});
232 if (!pair.second) {
233 ALOGE("%s: bufId %" PRIu64 " is already inflight!",
234 __FUNCTION__, bufferId);
235 return BAD_VALUE;
236 }
237 return OK;
238 }
239
240 // Find and pop a buffer_handle_t based on bufferId
popInflightRequestBuffer(uint64_t bufferId,buffer_handle_t ** buffer,int32_t * streamId)241 status_t BufferRecords::popInflightRequestBuffer(
242 uint64_t bufferId,
243 /*out*/ buffer_handle_t** buffer,
244 /*optional out*/ int32_t* streamId) {
245 if (buffer == nullptr) {
246 ALOGE("%s: buffer (%p) must not be null", __FUNCTION__, buffer);
247 return BAD_VALUE;
248 }
249 std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
250 auto it = mRequestedBufferMap.find(bufferId);
251 if (it == mRequestedBufferMap.end()) {
252 ALOGE("%s: bufId %" PRIu64 " is not inflight!",
253 __FUNCTION__, bufferId);
254 return BAD_VALUE;
255 }
256 *buffer = it->second.second;
257 if (streamId != nullptr) {
258 *streamId = it->second.first;
259 }
260 mRequestedBufferMap.erase(it);
261 return OK;
262 }
263
getInflightRequestBufferKeys(std::vector<uint64_t> * out)264 void BufferRecords::getInflightRequestBufferKeys(
265 std::vector<uint64_t>* out) {
266 std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
267 out->clear();
268 out->reserve(mRequestedBufferMap.size());
269 for (auto& pair : mRequestedBufferMap) {
270 out->push_back(pair.first);
271 }
272 return;
273 }
274
275
276 } // camera3
277 } // namespace android
278