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