1/*
2 * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "buffer_queue.h"
17
18#include <list>
19#include <string>
20
21#include "buffer_common.h"
22#include "buffer_manager.h"
23
24namespace OHOS {
25const int32_t BUFFER_STRIDE_ALIGNMENT_DEFAULT = 4;
26const uint8_t BUFFER_QUEUE_SIZE_DEFAULT = 1;
27const uint8_t BUFFER_QUEUE_SIZE_MAX = 10;
28const int32_t BUFFER_CONSUMER_USAGE_DEFAULT = BUFFER_CONSUMER_USAGE_SORTWARE;
29const uint8_t USER_DATA_COUNT = 100;
30
31BufferQueue::BufferQueue()
32    : width_(0),
33      height_(0),
34      format_(IMAGE_PIXEL_FORMAT_RGB565),
35      stride_(0),
36      usage_(BUFFER_CONSUMER_USAGE_DEFAULT),
37      size_(0),
38      queueSize_(BUFFER_QUEUE_SIZE_DEFAULT),
39      strideAlignment_(BUFFER_STRIDE_ALIGNMENT_DEFAULT),
40      attachCount_(0),
41      customSize_(false)
42{
43}
44
45BufferQueue::~BufferQueue()
46{
47    pthread_mutex_lock(&lock_);
48    freeList_.clear();
49    dirtyList_.clear();
50    std::list<SurfaceBufferImpl *>::iterator iterBuffer;
51    for (iterBuffer = allBuffers_.begin(); iterBuffer != allBuffers_.end(); ++iterBuffer) {
52        SurfaceBufferImpl* tmpBuffer = *iterBuffer;
53        BufferManager* bufferManager = BufferManager::GetInstance();
54        if (bufferManager == nullptr) {
55            continue;
56        }
57        bufferManager->FreeBuffer(&tmpBuffer);
58    }
59    allBuffers_.clear();
60    pthread_mutex_unlock(&lock_);
61    pthread_cond_destroy(&freeCond_);
62    pthread_mutex_destroy(&lock_);
63}
64
65bool BufferQueue::Init()
66{
67    if (pthread_mutex_init(&lock_, NULL)) {
68        GRAPHIC_LOGE("Failed init mutex");
69        return false;
70    }
71    if (pthread_cond_init(&freeCond_, NULL)) {
72        GRAPHIC_LOGE("Failed init cond");
73        pthread_mutex_destroy(&lock_);
74        return false;
75    }
76    return true;
77}
78
79void BufferQueue::NeedAttach()
80{
81    if (queueSize_ == attachCount_) {
82        GRAPHIC_LOGI("has alloced %d buffer, could not alloc more.", allBuffers_.size());
83        return;
84    }
85    if (size_ == 0 && isValidAttr(width_, height_, format_, strideAlignment_) != SURFACE_ERROR_OK) {
86        GRAPHIC_LOGI("Invalid Attr.");
87        return;
88    }
89    BufferManager* bufferManager = BufferManager::GetInstance();
90    RETURN_IF_FAIL(bufferManager);
91    SurfaceBufferImpl *buffer = nullptr;
92    if (size_ != 0 && customSize_) {
93        buffer = bufferManager->AllocBuffer(size_, usage_);
94    } else {
95        buffer = bufferManager->AllocBuffer(width_, height_, format_, usage_);
96    }
97    if (buffer == nullptr) {
98        GRAPHIC_LOGI("BufferManager alloc memory failed ");
99        return;
100    }
101    size_ = buffer->GetSize();
102    stride_ = buffer->GetStride();
103    attachCount_++;
104    freeList_.push_back(buffer);
105    allBuffers_.push_back(buffer);
106}
107
108bool BufferQueue::CanRequest(uint8_t wait)
109{
110    bool res = true;
111    if (!freeList_.empty()) {
112        res = true;
113        goto ERROR;
114    }
115    if (attachCount_ < queueSize_) {
116        NeedAttach();
117        res = true;
118        if (freeList_.empty()) {
119            GRAPHIC_LOGI("no buffer in freeQueue for dequeue.");
120            res = false;
121        }
122        goto ERROR;
123    }
124    if (wait) {
125        pthread_cond_wait(&freeCond_, &lock_);
126        res = true;
127    }
128ERROR:
129    return res;
130}
131
132SurfaceBufferImpl* BufferQueue::RequestBuffer(uint8_t wait)
133{
134    SurfaceBufferImpl *buffer = nullptr;
135    pthread_mutex_lock(&lock_);
136    if (!CanRequest(wait)) {
137        GRAPHIC_LOGI("No buffer can request now.");
138        goto ERROR;
139    }
140    buffer = freeList_.front();
141    if (buffer == nullptr) {
142        GRAPHIC_LOGI("freeQueue pop buffer failed.");
143        goto ERROR;
144    }
145    freeList_.pop_front();
146    buffer->SetState(BUFFER_STATE_REQUEST);
147ERROR:
148    pthread_mutex_unlock(&lock_);
149    return buffer;
150}
151
152SurfaceBufferImpl* BufferQueue::GetBuffer(const SurfaceBufferImpl& buffer)
153{
154    std::list<SurfaceBufferImpl *>::iterator iterBuffer;
155    for (iterBuffer = allBuffers_.begin(); iterBuffer != allBuffers_.end(); ++iterBuffer) {
156        SurfaceBufferImpl *tmpBuffer = *iterBuffer;
157        if (tmpBuffer->equals(buffer)) {
158            return tmpBuffer;
159        }
160    }
161    return nullptr;
162}
163
164int32_t BufferQueue::FlushBuffer(SurfaceBufferImpl& buffer)
165{
166    pthread_mutex_lock(&lock_);
167    SurfaceBufferImpl *tmpBuffer = GetBuffer(buffer);
168    if (tmpBuffer == nullptr || tmpBuffer->GetState() != BUFFER_STATE_REQUEST) {
169        GRAPHIC_LOGI("Buffer is not existed or state invailed.");
170        pthread_mutex_unlock(&lock_);
171        return SURFACE_ERROR_BUFFER_NOT_EXISTED;
172    }
173    dirtyList_.push_back(tmpBuffer);
174    if (&buffer != tmpBuffer) {
175        tmpBuffer->CopyExtraData(buffer);
176    }
177    tmpBuffer->SetState(BUFFER_STATE_FLUSH);
178    pthread_mutex_unlock(&lock_);
179    return 0;
180}
181
182SurfaceBufferImpl* BufferQueue::AcquireBuffer()
183{
184    pthread_mutex_lock(&lock_);
185    if (dirtyList_.empty()) {
186        pthread_mutex_unlock(&lock_);
187        GRAPHIC_LOGD("dirty queue is empty.");
188        return nullptr;
189    }
190    SurfaceBufferImpl *buffer = dirtyList_.front();
191    if (buffer == nullptr) {
192        pthread_mutex_unlock(&lock_);
193        GRAPHIC_LOGW("dirty queue pop buffer failed.");
194        return nullptr;
195    }
196    buffer->SetState(BUFFER_STATE_ACQUIRE);
197    dirtyList_.pop_front();
198    pthread_mutex_unlock(&lock_);
199    return buffer;
200}
201
202void BufferQueue::Detach(SurfaceBufferImpl *buffer)
203{
204    if (buffer == nullptr) {
205        GRAPHIC_LOGW("Detach buffer failed, buffer is null.");
206        return;
207    }
208    freeList_.remove(buffer);
209    dirtyList_.remove(buffer);
210    allBuffers_.remove(buffer);
211    BufferManager* bufferManager = BufferManager::GetInstance();
212    if (bufferManager != nullptr) {
213        bufferManager->FreeBuffer(&buffer);
214    }
215}
216
217bool BufferQueue::ReleaseBuffer(const SurfaceBufferImpl& buffer)
218{
219    return ReleaseBuffer(buffer, BUFFER_STATE_ACQUIRE) == SURFACE_ERROR_OK;
220}
221
222int32_t BufferQueue::CancelBuffer(const SurfaceBufferImpl& buffer)
223{
224    return ReleaseBuffer(buffer, BUFFER_STATE_REQUEST);
225}
226
227int32_t BufferQueue::ReleaseBuffer(const SurfaceBufferImpl& buffer, BufferState state)
228{
229    int32_t ret = 0;
230    pthread_mutex_lock(&lock_);
231    SurfaceBufferImpl *tmpBuffer = GetBuffer(buffer);
232    if (tmpBuffer == nullptr || tmpBuffer->GetState() != state) {
233        GRAPHIC_LOGI("Buffer is not existed or state invailed.");
234        ret = SURFACE_ERROR_BUFFER_NOT_EXISTED;
235        goto ERROR;
236    }
237
238    if (tmpBuffer->GetDeletePending() == 1) {
239        GRAPHIC_LOGI("Release the buffer which state is deletePending.");
240        Detach(tmpBuffer);
241        ret = SURFACE_ERROR_OK;
242        goto ERROR;
243    }
244
245    if (allBuffers_.size() > queueSize_) {
246        GRAPHIC_LOGI("Release the buffer: alloc buffer count is more than max queue count.");
247        attachCount_--;
248        Detach(tmpBuffer);
249        ret = SURFACE_ERROR_OK;
250        goto ERROR;
251    }
252
253    freeList_.push_back(tmpBuffer);
254    tmpBuffer->SetState(BUFFER_STATE_RELEASE);
255    tmpBuffer->ClearExtraData();
256ERROR:
257    pthread_mutex_unlock(&lock_);
258    pthread_cond_signal(&freeCond_);
259    return ret;
260}
261
262int32_t BufferQueue::isValidAttr(uint32_t width, uint32_t height, uint32_t format, uint32_t strideAlignment)
263{
264    if (width == 0 || height == 0 || strideAlignment <= 0
265        || format == IMAGE_PIXEL_FORMAT_NONE) {
266            return SURFACE_ERROR_INVALID_PARAM;
267    }
268    return SURFACE_ERROR_OK;
269}
270
271int32_t BufferQueue::Reset(uint32_t size)
272{
273    if (size == 0) {
274        if (isValidAttr(width_, height_, format_, strideAlignment_) != SURFACE_ERROR_OK) {
275            GRAPHIC_LOGI("Invalid Attr.");
276            return SURFACE_ERROR_INVALID_PARAM;
277        } else {
278            size_ = 0;
279            customSize_ = false;
280        }
281    }
282    std::list<SurfaceBufferImpl *>::iterator iterBuffer = freeList_.begin();
283    while (iterBuffer != freeList_.end()) {
284        SurfaceBufferImpl *tmpBuffer = *iterBuffer;
285        dirtyList_.remove(tmpBuffer);
286        allBuffers_.remove(tmpBuffer);
287        BufferManager* bufferManager = BufferManager::GetInstance();
288        if (bufferManager == nullptr) {
289             ++iterBuffer;
290            continue;
291        }
292        bufferManager->FreeBuffer(&tmpBuffer);
293        iterBuffer = freeList_.erase(iterBuffer);
294    }
295    for (iterBuffer = allBuffers_.begin(); iterBuffer != allBuffers_.end(); ++iterBuffer) {
296        SurfaceBufferImpl *tmpBuffer = *iterBuffer;
297        tmpBuffer->SetDeletePending(1);
298    }
299    attachCount_ = 0;
300    return 0;
301}
302
303void BufferQueue::SetQueueSize(uint8_t queueSize)
304{
305    if (queueSize > BUFFER_QUEUE_SIZE_MAX || queueSize == queueSize_) {
306        GRAPHIC_LOGI("The queue count(%u) is invalid", queueSize);
307        return;
308    }
309    pthread_mutex_lock(&lock_);
310    if (queueSize_ > queueSize) {
311        uint8_t needDelete = queueSize_ - queueSize;
312        std::list<SurfaceBufferImpl *>::iterator iterBuffer = freeList_.begin();
313        while (iterBuffer != freeList_.end()) {
314            SurfaceBufferImpl *tmpBuffer = *iterBuffer;
315            dirtyList_.remove(tmpBuffer);
316            allBuffers_.remove(tmpBuffer);
317            BufferManager* bufferManager = BufferManager::GetInstance();
318            if (bufferManager == nullptr) {
319                ++iterBuffer;
320                continue;
321            }
322            bufferManager->FreeBuffer(&tmpBuffer);
323            iterBuffer = freeList_.erase(iterBuffer);
324            needDelete--;
325            attachCount_--;
326            if (needDelete == 0) {
327                break;
328            }
329        }
330        queueSize_ = queueSize;
331        pthread_mutex_unlock(&lock_);
332    } else if (queueSize_ < queueSize) {
333        queueSize_ = queueSize;
334        pthread_mutex_unlock(&lock_);
335        pthread_cond_signal(&freeCond_);
336    }
337}
338
339uint8_t BufferQueue::GetQueueSize()
340{
341    return queueSize_;
342}
343
344void BufferQueue::SetWidthAndHeight(uint32_t width, uint32_t height)
345{
346    pthread_mutex_lock(&lock_);
347    width_ = width;
348    height_ = height;
349    Reset();
350    pthread_mutex_unlock(&lock_);
351    pthread_cond_signal(&freeCond_);
352}
353
354int32_t BufferQueue::GetWidth()
355{
356    return width_;
357}
358
359int32_t BufferQueue::GetHeight()
360{
361    return height_;
362}
363
364void BufferQueue::SetSize(uint32_t size)
365{
366    pthread_mutex_lock(&lock_);
367    size_ = size;
368    customSize_ = true;
369    Reset(size);
370    pthread_mutex_unlock(&lock_);
371    pthread_cond_signal(&freeCond_);
372}
373
374int32_t BufferQueue::GetSize()
375{
376    return size_;
377}
378
379void BufferQueue::SetUserData(const std::string& key, const std::string& value)
380{
381    if (usrDataMap_.size() > USER_DATA_COUNT) {
382        return;
383    }
384    usrDataMap_[key] = value;
385}
386
387std::string BufferQueue::GetUserData(const std::string& key)
388{
389    auto p = usrDataMap_.find(key);
390    if (p != usrDataMap_.end()) {
391        return p->second;
392    }
393    return std::string();
394}
395
396void BufferQueue::SetFormat(uint32_t format)
397{
398    if (format == IMAGE_PIXEL_FORMAT_NONE) {
399        GRAPHIC_LOGI("Format is invailed or not supported %u", format);
400        return;
401    }
402    pthread_mutex_lock(&lock_);
403    format_ = format;
404    Reset();
405    pthread_mutex_unlock(&lock_);
406    pthread_cond_signal(&freeCond_);
407}
408
409int32_t BufferQueue::GetFormat()
410{
411    return format_;
412}
413
414void BufferQueue::SetStrideAlignment(uint32_t stride)
415{
416    pthread_mutex_lock(&lock_);
417    strideAlignment_ = stride;
418    Reset();
419    pthread_mutex_unlock(&lock_);
420    pthread_cond_signal(&freeCond_);
421}
422
423int32_t BufferQueue::GetStrideAlignment()
424{
425    return strideAlignment_;
426}
427
428int32_t BufferQueue::GetStride()
429{
430    return stride_;
431}
432
433void BufferQueue::SetUsage(uint32_t usage)
434{
435    pthread_mutex_lock(&lock_);
436    usage_ = usage;
437    Reset();
438    pthread_mutex_unlock(&lock_);
439    pthread_cond_signal(&freeCond_);
440}
441
442int32_t BufferQueue::GetUsage()
443{
444    return usage_;
445}
446} // end namespace
447