blob: cc2939062e1581d3ceaa69d51630acf3180635ff [file] [log] [blame]
Yin-Chia Yeh5fd603e2019-11-20 11:22:27 -08001/*
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
28namespace android {
29namespace camera3 {
30
31camera3_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 CAMERA3_BUFFER_STATUS_OK;
36 case BufferStatus::ERROR: return CAMERA3_BUFFER_STATUS_ERROR;
37 }
38 return CAMERA3_BUFFER_STATUS_ERROR;
39}
40
41void 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
51void 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
61void 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
73std::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
89void 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
96void 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
109uint64_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
134std::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
151bool BufferRecords::isStreamCached(int streamId) {
152 std::lock_guard<std::mutex> lock(mBufferIdMapLock);
153 return mBufferIdMaps.find(streamId) != mBufferIdMaps.end();
154}
155
156bool 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
182void 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
196status_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
204status_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
219void 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
228status_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
241status_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
264void 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