1 /*
2  * Copyright (C) 2023 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_NDEBUG 0
18 
19 #include "Buffer.h"
20 #include <inttypes.h>
21 #include <log/log.h>
22 
23 namespace android {
24 namespace webcam {
25 
BufferManager(BufferCreatorAndDestroyer * crD)26 BufferManager::BufferManager(BufferCreatorAndDestroyer* crD) : mCrD(crD) {
27     if (crD == nullptr) {
28         return;
29     }
30 
31     std::vector<std::shared_ptr<Buffer>> producerBuffers;
32     if (mCrD->allocateAndMapBuffers(&mConsumerBufferItem.buffer, &producerBuffers) != Status::OK) {
33         return;
34     }
35     mConsumerBufferItem.state = BufferState::FREE;
36     for (auto& buf : producerBuffers) {
37         mProducerBufferItems.emplace_back(buf, BufferState::FREE);
38     }
39     mInited = true;
40 }
41 
~BufferManager()42 BufferManager::~BufferManager() {
43     std::vector<std::shared_ptr<Buffer>> producerBuffers;
44     for (auto& buf : mProducerBufferItems) {
45         producerBuffers.push_back(buf.buffer);
46     }
47     mCrD->destroyBuffers(mConsumerBufferItem.buffer, producerBuffers);
48     mConsumerBufferItem.buffer = nullptr;
49     mProducerBufferItems.clear();
50 }
51 
getFreeBufferIfAvailable()52 Buffer* BufferManager::getFreeBufferIfAvailable() {
53     // Producer call
54     std::unique_lock<std::mutex> l(mBufferLock);
55     for (auto& bufferItem : mProducerBufferItems) {
56         if (bufferItem.state == BufferState::FREE) {
57             bufferItem.state = BufferState::IN_USE;
58             return bufferItem.buffer.get();
59         }
60     }
61     for (const auto& bufferItem : mProducerBufferItems) {
62         uint64_t bufferTs = bufferItem.buffer->getTimestamp();
63         ALOGV("%s: Buffer at state %d, ts %" PRIu64 ", v4l2 index %u",
64               __FUNCTION__, (int)bufferItem.state, bufferTs,
65               bufferItem.buffer->getIndex());
66     }
67     return nullptr;
68 }
69 
filledProducerBufferAvailableLocked(uint32_t * index)70 bool BufferManager::filledProducerBufferAvailableLocked(uint32_t* index) {
71     uint32_t i = 0;
72     bool found = false;
73     uint32_t foundIndex = 0;
74     uint64_t ts = 0;
75     // Try to get the latest filled buffer.
76     for (auto& bufferItem : mProducerBufferItems) {
77         uint64_t bufferTs = bufferItem.buffer->getTimestamp();
78         ALOGV("%s: Buffer at index i %u : state %d, ts %" PRIu64 ", v4l2 index %u", __FUNCTION__,
79                 i, (int)bufferItem.state, bufferTs, bufferItem.buffer->getIndex());
80         if (bufferItem.state == BufferState::FILLED) {
81             if (bufferTs > ts) {
82                 if (index != nullptr) {
83                     *index = i;
84                 }
85                 ts = bufferTs;
86                 found = true;
87                 foundIndex = i;
88             }
89         }
90         i++;
91     }
92     // Actually cancel older buffers
93     uint32_t j = 0;
94     for (auto& bufferItem : mProducerBufferItems) {
95         if (bufferItem.state == BufferState::FILLED && j != foundIndex) {
96             bufferItem.state = BufferState::FREE;
97         }
98         j++;
99     }
100     return found;
101 }
102 
getFilledBufferAndSwap()103 Buffer* BufferManager::getFilledBufferAndSwap() {
104     // Consumer call
105     // Wait for a producer buffer item state to be FILLED
106     // and swap consumer and producer buffer
107     std::unique_lock<std::mutex> l(mBufferLock);
108     uint32_t index = 0;
109     while (!filledProducerBufferAvailableLocked(&index)) {
110         // TODO(b/267794640): Add a timeout to recover in case of a deadlock.
111         // Wait till the producer side has filled the buffer.
112         mProducerBufferFilled.wait(l);
113     }
114     // Mark it free so that the producer can start filling it.
115     mConsumerBufferItem.state = BufferState::FREE;
116     std::swap(mConsumerBufferItem, mProducerBufferItems[index]);
117     // Now the consumer buffer is busy
118     mConsumerBufferItem.state = BufferState::IN_USE;
119     return mConsumerBufferItem.buffer.get();
120 }
121 
changeProducerBufferStateLocked(Buffer * buffer,BufferState newState)122 bool BufferManager::changeProducerBufferStateLocked(Buffer* buffer, BufferState newState) {
123     bool found = false;
124     uint32_t i = 0;
125     for (auto& bufferItem : mProducerBufferItems) {
126         if (buffer->getIndex() == bufferItem.buffer->getIndex()) {
127             found = true;
128             break;
129         }
130         i++;
131     }
132     if (!found) {
133         ALOGE("%s queuing incorrect buffer, filled buffer index %u", __FUNCTION__,
134               buffer->getIndex());
135         return false;
136     }
137 
138     mProducerBufferItems[i].state = newState;
139     return true;
140 }
141 
cancelBuffer(Buffer * buffer)142 Status BufferManager::cancelBuffer(Buffer* buffer) {
143     std::unique_lock<std::mutex> l(mBufferLock);
144     if (!changeProducerBufferStateLocked(buffer, BufferState::FREE)) {
145         return Status::ERROR;
146     }
147     return Status::OK;
148 }
149 
queueFilledBuffer(Buffer * buffer)150 Status BufferManager::queueFilledBuffer(Buffer* buffer) {
151     std::unique_lock<std::mutex> l(mBufferLock);
152 
153     if (!changeProducerBufferStateLocked(buffer, BufferState::FILLED)) {
154         return Status::ERROR;
155     }
156 
157     mProducerBufferFilled.notify_one();
158     return Status::OK;
159 }
160 
161 }  // namespace webcam
162 }  // namespace android
163