mirror of
https://github.com/openharmony/graphic_surface_lite.git
synced 2026-07-18 19:04:32 -04:00
b3a7909baa
Change-Id: Idd3ff062985e7f0b53f39299c69ba4fa329b8ebf Signed-off-by: liuyuxiang-bear <liuyuxiang7@huawei.com>
447 lines
12 KiB
C++
447 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2020-2022 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "buffer_queue.h"
|
|
|
|
#include <list>
|
|
#include <string>
|
|
|
|
#include "buffer_common.h"
|
|
#include "buffer_manager.h"
|
|
|
|
namespace OHOS {
|
|
const int32_t BUFFER_STRIDE_ALIGNMENT_DEFAULT = 4;
|
|
const uint8_t BUFFER_QUEUE_SIZE_DEFAULT = 1;
|
|
const uint8_t BUFFER_QUEUE_SIZE_MAX = 10;
|
|
const int32_t BUFFER_CONSUMER_USAGE_DEFAULT = BUFFER_CONSUMER_USAGE_SORTWARE;
|
|
const uint8_t USER_DATA_COUNT = 100;
|
|
|
|
BufferQueue::BufferQueue()
|
|
: width_(0),
|
|
height_(0),
|
|
format_(IMAGE_PIXEL_FORMAT_RGB565),
|
|
stride_(0),
|
|
usage_(BUFFER_CONSUMER_USAGE_DEFAULT),
|
|
size_(0),
|
|
queueSize_(BUFFER_QUEUE_SIZE_DEFAULT),
|
|
strideAlignment_(BUFFER_STRIDE_ALIGNMENT_DEFAULT),
|
|
attachCount_(0),
|
|
customSize_(false)
|
|
{
|
|
}
|
|
|
|
BufferQueue::~BufferQueue()
|
|
{
|
|
pthread_mutex_lock(&lock_);
|
|
freeList_.clear();
|
|
dirtyList_.clear();
|
|
std::list<SurfaceBufferImpl *>::iterator iterBuffer;
|
|
for (iterBuffer = allBuffers_.begin(); iterBuffer != allBuffers_.end(); ++iterBuffer) {
|
|
SurfaceBufferImpl* tmpBuffer = *iterBuffer;
|
|
BufferManager* bufferManager = BufferManager::GetInstance();
|
|
if (bufferManager == nullptr) {
|
|
continue;
|
|
}
|
|
bufferManager->FreeBuffer(&tmpBuffer);
|
|
}
|
|
allBuffers_.clear();
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_destroy(&freeCond_);
|
|
pthread_mutex_destroy(&lock_);
|
|
}
|
|
|
|
bool BufferQueue::Init()
|
|
{
|
|
if (pthread_mutex_init(&lock_, NULL)) {
|
|
GRAPHIC_LOGE("Failed init mutex");
|
|
return false;
|
|
}
|
|
if (pthread_cond_init(&freeCond_, NULL)) {
|
|
GRAPHIC_LOGE("Failed init cond");
|
|
pthread_mutex_destroy(&lock_);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void BufferQueue::NeedAttach()
|
|
{
|
|
if (queueSize_ == attachCount_) {
|
|
GRAPHIC_LOGI("has alloced %d buffer, could not alloc more.", allBuffers_.size());
|
|
return;
|
|
}
|
|
if (size_ == 0 && isValidAttr(width_, height_, format_, strideAlignment_) != SURFACE_ERROR_OK) {
|
|
GRAPHIC_LOGI("Invalid Attr.");
|
|
return;
|
|
}
|
|
BufferManager* bufferManager = BufferManager::GetInstance();
|
|
RETURN_IF_FAIL(bufferManager);
|
|
SurfaceBufferImpl *buffer = nullptr;
|
|
if (size_ != 0 && customSize_) {
|
|
buffer = bufferManager->AllocBuffer(size_, usage_);
|
|
} else {
|
|
buffer = bufferManager->AllocBuffer(width_, height_, format_, usage_);
|
|
}
|
|
if (buffer == nullptr) {
|
|
GRAPHIC_LOGI("BufferManager alloc memory failed ");
|
|
return;
|
|
}
|
|
size_ = buffer->GetSize();
|
|
stride_ = buffer->GetStride();
|
|
attachCount_++;
|
|
freeList_.push_back(buffer);
|
|
allBuffers_.push_back(buffer);
|
|
}
|
|
|
|
bool BufferQueue::CanRequest(uint8_t wait)
|
|
{
|
|
bool res = true;
|
|
if (!freeList_.empty()) {
|
|
res = true;
|
|
goto ERROR;
|
|
}
|
|
if (attachCount_ < queueSize_) {
|
|
NeedAttach();
|
|
res = true;
|
|
if (freeList_.empty()) {
|
|
GRAPHIC_LOGI("no buffer in freeQueue for dequeue.");
|
|
res = false;
|
|
}
|
|
goto ERROR;
|
|
}
|
|
if (wait) {
|
|
pthread_cond_wait(&freeCond_, &lock_);
|
|
res = true;
|
|
}
|
|
ERROR:
|
|
return res;
|
|
}
|
|
|
|
SurfaceBufferImpl* BufferQueue::RequestBuffer(uint8_t wait)
|
|
{
|
|
SurfaceBufferImpl *buffer = nullptr;
|
|
pthread_mutex_lock(&lock_);
|
|
if (!CanRequest(wait)) {
|
|
GRAPHIC_LOGI("No buffer can request now.");
|
|
goto ERROR;
|
|
}
|
|
buffer = freeList_.front();
|
|
if (buffer == nullptr) {
|
|
GRAPHIC_LOGI("freeQueue pop buffer failed.");
|
|
goto ERROR;
|
|
}
|
|
freeList_.pop_front();
|
|
buffer->SetState(BUFFER_STATE_REQUEST);
|
|
ERROR:
|
|
pthread_mutex_unlock(&lock_);
|
|
return buffer;
|
|
}
|
|
|
|
SurfaceBufferImpl* BufferQueue::GetBuffer(const SurfaceBufferImpl& buffer)
|
|
{
|
|
std::list<SurfaceBufferImpl *>::iterator iterBuffer;
|
|
for (iterBuffer = allBuffers_.begin(); iterBuffer != allBuffers_.end(); ++iterBuffer) {
|
|
SurfaceBufferImpl *tmpBuffer = *iterBuffer;
|
|
if (tmpBuffer->equals(buffer)) {
|
|
return tmpBuffer;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
int32_t BufferQueue::FlushBuffer(SurfaceBufferImpl& buffer)
|
|
{
|
|
pthread_mutex_lock(&lock_);
|
|
SurfaceBufferImpl *tmpBuffer = GetBuffer(buffer);
|
|
if (tmpBuffer == nullptr || tmpBuffer->GetState() != BUFFER_STATE_REQUEST) {
|
|
GRAPHIC_LOGI("Buffer is not existed or state invailed.");
|
|
pthread_mutex_unlock(&lock_);
|
|
return SURFACE_ERROR_BUFFER_NOT_EXISTED;
|
|
}
|
|
dirtyList_.push_back(tmpBuffer);
|
|
if (&buffer != tmpBuffer) {
|
|
tmpBuffer->CopyExtraData(buffer);
|
|
}
|
|
tmpBuffer->SetState(BUFFER_STATE_FLUSH);
|
|
pthread_mutex_unlock(&lock_);
|
|
return 0;
|
|
}
|
|
|
|
SurfaceBufferImpl* BufferQueue::AcquireBuffer()
|
|
{
|
|
pthread_mutex_lock(&lock_);
|
|
if (dirtyList_.empty()) {
|
|
pthread_mutex_unlock(&lock_);
|
|
GRAPHIC_LOGD("dirty queue is empty.");
|
|
return nullptr;
|
|
}
|
|
SurfaceBufferImpl *buffer = dirtyList_.front();
|
|
if (buffer == nullptr) {
|
|
pthread_mutex_unlock(&lock_);
|
|
GRAPHIC_LOGW("dirty queue pop buffer failed.");
|
|
return nullptr;
|
|
}
|
|
buffer->SetState(BUFFER_STATE_ACQUIRE);
|
|
dirtyList_.pop_front();
|
|
pthread_mutex_unlock(&lock_);
|
|
return buffer;
|
|
}
|
|
|
|
void BufferQueue::Detach(SurfaceBufferImpl *buffer)
|
|
{
|
|
if (buffer == nullptr) {
|
|
GRAPHIC_LOGW("Detach buffer failed, buffer is null.");
|
|
return;
|
|
}
|
|
freeList_.remove(buffer);
|
|
dirtyList_.remove(buffer);
|
|
allBuffers_.remove(buffer);
|
|
BufferManager* bufferManager = BufferManager::GetInstance();
|
|
if (bufferManager != nullptr) {
|
|
bufferManager->FreeBuffer(&buffer);
|
|
}
|
|
}
|
|
|
|
bool BufferQueue::ReleaseBuffer(const SurfaceBufferImpl& buffer)
|
|
{
|
|
return ReleaseBuffer(buffer, BUFFER_STATE_ACQUIRE) == SURFACE_ERROR_OK;
|
|
}
|
|
|
|
int32_t BufferQueue::CancelBuffer(const SurfaceBufferImpl& buffer)
|
|
{
|
|
return ReleaseBuffer(buffer, BUFFER_STATE_REQUEST);
|
|
}
|
|
|
|
int32_t BufferQueue::ReleaseBuffer(const SurfaceBufferImpl& buffer, BufferState state)
|
|
{
|
|
int32_t ret = 0;
|
|
pthread_mutex_lock(&lock_);
|
|
SurfaceBufferImpl *tmpBuffer = GetBuffer(buffer);
|
|
if (tmpBuffer == nullptr || tmpBuffer->GetState() != state) {
|
|
GRAPHIC_LOGI("Buffer is not existed or state invailed.");
|
|
ret = SURFACE_ERROR_BUFFER_NOT_EXISTED;
|
|
goto ERROR;
|
|
}
|
|
|
|
if (tmpBuffer->GetDeletePending() == 1) {
|
|
GRAPHIC_LOGI("Release the buffer which state is deletePending.");
|
|
Detach(tmpBuffer);
|
|
ret = SURFACE_ERROR_OK;
|
|
goto ERROR;
|
|
}
|
|
|
|
if (allBuffers_.size() > queueSize_) {
|
|
GRAPHIC_LOGI("Release the buffer: alloc buffer count is more than max queue count.");
|
|
attachCount_--;
|
|
Detach(tmpBuffer);
|
|
ret = SURFACE_ERROR_OK;
|
|
goto ERROR;
|
|
}
|
|
|
|
freeList_.push_back(tmpBuffer);
|
|
tmpBuffer->SetState(BUFFER_STATE_RELEASE);
|
|
tmpBuffer->ClearExtraData();
|
|
ERROR:
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_signal(&freeCond_);
|
|
return ret;
|
|
}
|
|
|
|
int32_t BufferQueue::isValidAttr(uint32_t width, uint32_t height, uint32_t format, uint32_t strideAlignment)
|
|
{
|
|
if (width == 0 || height == 0 || strideAlignment <= 0
|
|
|| format == IMAGE_PIXEL_FORMAT_NONE) {
|
|
return SURFACE_ERROR_INVALID_PARAM;
|
|
}
|
|
return SURFACE_ERROR_OK;
|
|
}
|
|
|
|
int32_t BufferQueue::Reset(uint32_t size)
|
|
{
|
|
if (size == 0) {
|
|
if (isValidAttr(width_, height_, format_, strideAlignment_) != SURFACE_ERROR_OK) {
|
|
GRAPHIC_LOGI("Invalid Attr.");
|
|
return SURFACE_ERROR_INVALID_PARAM;
|
|
} else {
|
|
size_ = 0;
|
|
customSize_ = false;
|
|
}
|
|
}
|
|
std::list<SurfaceBufferImpl *>::iterator iterBuffer = freeList_.begin();
|
|
while (iterBuffer != freeList_.end()) {
|
|
SurfaceBufferImpl *tmpBuffer = *iterBuffer;
|
|
dirtyList_.remove(tmpBuffer);
|
|
allBuffers_.remove(tmpBuffer);
|
|
BufferManager* bufferManager = BufferManager::GetInstance();
|
|
if (bufferManager == nullptr) {
|
|
++iterBuffer;
|
|
continue;
|
|
}
|
|
bufferManager->FreeBuffer(&tmpBuffer);
|
|
iterBuffer = freeList_.erase(iterBuffer);
|
|
}
|
|
for (iterBuffer = allBuffers_.begin(); iterBuffer != allBuffers_.end(); ++iterBuffer) {
|
|
SurfaceBufferImpl *tmpBuffer = *iterBuffer;
|
|
tmpBuffer->SetDeletePending(1);
|
|
}
|
|
attachCount_ = 0;
|
|
return 0;
|
|
}
|
|
|
|
void BufferQueue::SetQueueSize(uint8_t queueSize)
|
|
{
|
|
if (queueSize > BUFFER_QUEUE_SIZE_MAX || queueSize == queueSize_) {
|
|
GRAPHIC_LOGI("The queue count(%u) is invalid", queueSize);
|
|
return;
|
|
}
|
|
pthread_mutex_lock(&lock_);
|
|
if (queueSize_ > queueSize) {
|
|
uint8_t needDelete = queueSize_ - queueSize;
|
|
std::list<SurfaceBufferImpl *>::iterator iterBuffer = freeList_.begin();
|
|
while (iterBuffer != freeList_.end()) {
|
|
SurfaceBufferImpl *tmpBuffer = *iterBuffer;
|
|
dirtyList_.remove(tmpBuffer);
|
|
allBuffers_.remove(tmpBuffer);
|
|
BufferManager* bufferManager = BufferManager::GetInstance();
|
|
if (bufferManager == nullptr) {
|
|
++iterBuffer;
|
|
continue;
|
|
}
|
|
bufferManager->FreeBuffer(&tmpBuffer);
|
|
iterBuffer = freeList_.erase(iterBuffer);
|
|
needDelete--;
|
|
attachCount_--;
|
|
if (needDelete == 0) {
|
|
break;
|
|
}
|
|
}
|
|
queueSize_ = queueSize;
|
|
pthread_mutex_unlock(&lock_);
|
|
} else if (queueSize_ < queueSize) {
|
|
queueSize_ = queueSize;
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_signal(&freeCond_);
|
|
}
|
|
}
|
|
|
|
uint8_t BufferQueue::GetQueueSize()
|
|
{
|
|
return queueSize_;
|
|
}
|
|
|
|
void BufferQueue::SetWidthAndHeight(uint32_t width, uint32_t height)
|
|
{
|
|
pthread_mutex_lock(&lock_);
|
|
width_ = width;
|
|
height_ = height;
|
|
Reset();
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_signal(&freeCond_);
|
|
}
|
|
|
|
int32_t BufferQueue::GetWidth()
|
|
{
|
|
return width_;
|
|
}
|
|
|
|
int32_t BufferQueue::GetHeight()
|
|
{
|
|
return height_;
|
|
}
|
|
|
|
void BufferQueue::SetSize(uint32_t size)
|
|
{
|
|
pthread_mutex_lock(&lock_);
|
|
size_ = size;
|
|
customSize_ = true;
|
|
Reset(size);
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_signal(&freeCond_);
|
|
}
|
|
|
|
int32_t BufferQueue::GetSize()
|
|
{
|
|
return size_;
|
|
}
|
|
|
|
void BufferQueue::SetUserData(const std::string& key, const std::string& value)
|
|
{
|
|
if (usrDataMap_.size() > USER_DATA_COUNT) {
|
|
return;
|
|
}
|
|
usrDataMap_[key] = value;
|
|
}
|
|
|
|
std::string BufferQueue::GetUserData(const std::string& key)
|
|
{
|
|
auto p = usrDataMap_.find(key);
|
|
if (p != usrDataMap_.end()) {
|
|
return p->second;
|
|
}
|
|
return std::string();
|
|
}
|
|
|
|
void BufferQueue::SetFormat(uint32_t format)
|
|
{
|
|
if (format == IMAGE_PIXEL_FORMAT_NONE) {
|
|
GRAPHIC_LOGI("Format is invailed or not supported %u", format);
|
|
return;
|
|
}
|
|
pthread_mutex_lock(&lock_);
|
|
format_ = format;
|
|
Reset();
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_signal(&freeCond_);
|
|
}
|
|
|
|
int32_t BufferQueue::GetFormat()
|
|
{
|
|
return format_;
|
|
}
|
|
|
|
void BufferQueue::SetStrideAlignment(uint32_t stride)
|
|
{
|
|
pthread_mutex_lock(&lock_);
|
|
strideAlignment_ = stride;
|
|
Reset();
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_signal(&freeCond_);
|
|
}
|
|
|
|
int32_t BufferQueue::GetStrideAlignment()
|
|
{
|
|
return strideAlignment_;
|
|
}
|
|
|
|
int32_t BufferQueue::GetStride()
|
|
{
|
|
return stride_;
|
|
}
|
|
|
|
void BufferQueue::SetUsage(uint32_t usage)
|
|
{
|
|
pthread_mutex_lock(&lock_);
|
|
usage_ = usage;
|
|
Reset();
|
|
pthread_mutex_unlock(&lock_);
|
|
pthread_cond_signal(&freeCond_);
|
|
}
|
|
|
|
int32_t BufferQueue::GetUsage()
|
|
{
|
|
return usage_;
|
|
}
|
|
} // end namespace
|