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