* Copyright (c) 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 "allocator.h"
#include <cinttypes>
#include "display_common.h"
namespace OHOS {
namespace HDI {
namespace DISPLAY {
void Allocator::DumpBufferHandle(BufferHandle &handle) const
{
DISPLAY_LOGD("size %{public}d, width %{public}d height %{public}d stride %{public}d fd %{public}d format: %d",
handle.size, handle.width, handle.height, handle.stride, handle.fd, handle.format);
DISPLAY_LOGD("usage = 0x%{public}" PRIx64 "", handle.usage);
}
bool Allocator::IsYuv(PixelFormat format)
{
switch (format) {
case PIXEL_FMT_YCBCR_420_P:
case PIXEL_FMT_YUV_422_I:
case PIXEL_FMT_YCBCR_422_SP:
case PIXEL_FMT_YCRCB_422_SP:
case PIXEL_FMT_YCBCR_420_SP:
case PIXEL_FMT_YCRCB_420_SP:
case PIXEL_FMT_YCBCR_422_P:
case PIXEL_FMT_YCRCB_422_P:
case PIXEL_FMT_YCRCB_420_P:
case PIXEL_FMT_YUYV_422_PKG:
case PIXEL_FMT_UYVY_422_PKG:
case PIXEL_FMT_YVYU_422_PKG:
case PIXEL_FMT_VYUY_422_PKG:
return true;
default:
return false;
}
}
uint32_t Allocator::UpdatePixelInfo(BufferInfo &bufferInfo)
{
DISPLAY_LOGD("format is %{public}d", bufferInfo.format_);
if (IsYuv(bufferInfo.format_)) {
bufferInfo.bitsPerPixel_ = 8;
} else {
switch (bufferInfo.format_) {
case PIXEL_FMT_RGBX_8888:
case PIXEL_FMT_RGBA_8888:
case PIXEL_FMT_BGRX_8888:
case PIXEL_FMT_BGRA_8888:
bufferInfo.bitsPerPixel_ = 32;
break;
case PIXEL_FMT_RGB_888:
bufferInfo.bitsPerPixel_ = 24;
break;
case PIXEL_FMT_RGB_565:
case PIXEL_FMT_BGRX_4444:
case PIXEL_FMT_BGRA_4444:
case PIXEL_FMT_RGBA_4444:
case PIXEL_FMT_RGBX_4444:
case PIXEL_FMT_BGRX_5551:
case PIXEL_FMT_BGRA_5551:
bufferInfo.bitsPerPixel_ = 16;
break;
default:
DISPLAY_LOGE("the format can not support %{public}d", bufferInfo.format_);
return DISPLAY_NOT_SUPPORT;
}
}
bufferInfo.bytesPerPixel_ = bufferInfo.bitsPerPixel_ / BITS_PER_BYTES;
return DISPLAY_SUCCESS;
}
int32_t Allocator::UpdateRGBStrideAndSize(BufferInfo &bufferInfo)
{
bufferInfo.widthStride_ = AlignUp(bufferInfo.width_, WIDTH_ALIGN);
bufferInfo.heightStride_ = AlignUp(bufferInfo.height_, HEIGHT_ALIGN);
bufferInfo.size_ = bufferInfo.widthStride_ * bufferInfo.heightStride_ * bufferInfo.bytesPerPixel_;
return DISPLAY_SUCCESS;
}
int32_t Allocator::UpdateYuvStrideAndSize(BufferInfo &bufferInfo)
{
int32_t ret = DISPLAY_NOT_SUPPORT;
constexpr uint32_t UV_DIV_420 = 2;
DISPLAY_LOGD();
bufferInfo.widthStride_ = AlignUp(bufferInfo.width_, WIDTH_ALIGN);
bufferInfo.heightStride_ = AlignUp(bufferInfo.height_, HEIGHT_ALIGN);
switch (bufferInfo.format_) {
case PIXEL_FMT_YCBCR_420_P:
case PIXEL_FMT_YCBCR_422_SP:
case PIXEL_FMT_YCRCB_422_SP:
case PIXEL_FMT_YCBCR_420_SP:
case PIXEL_FMT_YCRCB_420_SP:
case PIXEL_FMT_YCRCB_420_P:
bufferInfo.heightStride_ = (bufferInfo.heightStride_ + bufferInfo.heightStride_ / UV_DIV_420);
ret = DISPLAY_SUCCESS;
break;
case PIXEL_FMT_YCBCR_422_P:
case PIXEL_FMT_YCRCB_422_P:
bufferInfo.heightStride_ = (bufferInfo.heightStride_ + bufferInfo.heightStride_);
bufferInfo.size_ = bufferInfo.widthStride_ * bufferInfo.heightStride_;
ret = DISPLAY_SUCCESS;
break;
default:
break;
}
return ret;
}
int32_t Allocator::UpdateStrideAndSize(BufferInfo &bufferInfo)
{
if (IsYuv(bufferInfo.format_)) {
return UpdateYuvStrideAndSize(bufferInfo);
} else {
return UpdateRGBStrideAndSize(bufferInfo);
}
}
int32_t Allocator::ConvertToBufferInfo(BufferInfo &bufferInfo, const AllocInfo &info)
{
DISPLAY_LOGD();
bufferInfo.width_ = info.width;
bufferInfo.height_ = info.height;
bufferInfo.format_ = info.format;
bufferInfo.usage_ = info.usage;
int32_t ret = UpdatePixelInfo(bufferInfo);
DISPLAY_CHK_RETURN(
(ret != DISPLAY_SUCCESS), DISPLAY_NOT_SUPPORT, DISPLAY_LOGE("failed to update pixel information"));
ret = UpdateStrideAndSize(bufferInfo);
DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_NOT_SUPPORT, DISPLAY_LOGE("failed to update stride and size"));
return DISPLAY_SUCCESS;
}
int32_t Allocator::Init()
{
DISPLAY_LOGD();
return DISPLAY_SUCCESS;
}
int32_t Allocator::AllocMem(const AllocInfo &info, BufferHandle **handle)
{
int ret;
DISPLAY_LOGD();
BufferInfo bufferInfo;
ret = ConvertToBufferInfo(bufferInfo, info);
DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_NOT_SUPPORT, DISPLAY_LOGE("failed to convert to bufferInfo"));
BufferHandle *priBuffer = reinterpret_cast<BufferHandle *>(malloc(sizeof(BufferHandle)));
DISPLAY_CHK_RETURN((priBuffer == nullptr), DISPLAY_NOT_SUPPORT, DISPLAY_LOGE("can not alloc memory"));
(void)memset_s(priBuffer, sizeof(BufferHandle), 0, sizeof(BufferHandle));
priBuffer->fd = -1;
priBuffer->width = bufferInfo.width_;
priBuffer->height = bufferInfo.height_;
priBuffer->stride = bufferInfo.widthStride_ * bufferInfo.bytesPerPixel_;
priBuffer->size = bufferInfo.size_;
priBuffer->format = bufferInfo.format_;
priBuffer->usage = bufferInfo.usage_;
ret = Allocate(bufferInfo, *priBuffer);
DumpBufferHandle(*priBuffer);
if (ret != DISPLAY_SUCCESS) {
DISPLAY_LOGE("AllocMem failed");
free(priBuffer);
priBuffer = nullptr;
return ret;
}
*handle = priBuffer;
return DISPLAY_SUCCESS;
}
int32_t Allocator::Allocate(const BufferInfo &bufferInfo, BufferHandle &handle)
{
DISPLAY_LOGE("AllocMem do not implement");
return DISPLAY_NOT_SUPPORT;
}
int32_t Allocator::FreeMem(BufferHandle *handle)
{
DISPLAY_LOGD();
DISPLAY_CHK_RETURN((handle == nullptr), DISPLAY_NULL_PTR, DISPLAY_LOGE("buffer is null"));
if (handle->fd >= 0) {
DISPLAY_LOGD("release the fd is %{public}d", handle->fd);
close(handle->fd);
handle->fd = -1;
}
const uint32_t reserveFds = handle->reserveFds;
for (uint32_t i = 0; i < reserveFds; i++) {
if (handle->reserve[i] >= 0) {
DISPLAY_LOGD("release the fd is %{public}d", handle->reserve[i]);
close(handle->reserve[i]);
handle->reserve[i] = -1;
}
}
free(handle);
return DISPLAY_SUCCESS;
}
int32_t Allocator::DmaBufferSync(const BufferHandle &handle, uint64_t flag)
{
if (handle.fd < 0) {
DISPLAY_LOGW("dmabuffer fd is invalid can not sync");
return DISPLAY_SUCCESS;
}
struct dma_buf_sync syncPrm = {0};
errno_t eok = memset_s(&syncPrm, sizeof(syncPrm), 0, sizeof(syncPrm));
DISPLAY_CHK_RETURN((eok != EOK), DISPLAY_PARAM_ERR, DISPLAY_LOGE("dma buffer sync memset_s failed"));
if (handle.usage & HBM_USE_CPU_WRITE) {
syncPrm.flags |= DMA_BUF_SYNC_WRITE;
}
if (handle.usage & HBM_USE_CPU_READ) {
syncPrm.flags |= DMA_BUF_SYNC_READ;
}
const int32_t retryMaxCount = 6;
int32_t retryCount = 0;
for (retryCount = 0; retryCount < retryMaxCount; retryCount++) {
int ret = ioctl(handle.fd, DMA_BUF_IOCTL_SYNC, &syncPrm);
if ((ret != -EAGAIN) && (ret != -EINTR)) {
break;
}
}
if (retryCount >= retryMaxCount) {
DISPLAY_LOGE("sync failed");
return DISPLAY_SYS_BUSY;
}
return DISPLAY_SUCCESS;
}
int32_t Allocator::InvalidateCache(BufferHandle &handle)
{
DISPLAY_LOGD();
return DmaBufferSync(handle, DMA_BUF_SYNC_END);
}
int32_t Allocator::FlushCache(BufferHandle &handle)
{
DISPLAY_LOGD();
return DmaBufferSync(handle, DMA_BUF_SYNC_START);
}
void *Allocator::Mmap(BufferHandle &handle)
{
DISPLAY_LOGD();
void *virAddr = nullptr;
if (handle.virAddr != nullptr) {
DISPLAY_LOGW("the buffer has virtual addr");
return handle.virAddr;
}
virAddr = mmap(nullptr, handle.size, PROT_READ | PROT_WRITE, MAP_SHARED, handle.fd, 0);
if (virAddr == MAP_FAILED) {
DISPLAY_LOGE("mmap failed errno %{public}d, fd : %{public}d", errno, handle.fd);
handle.virAddr = nullptr;
return nullptr;
}
handle.virAddr = virAddr;
return virAddr;
}
int32_t Allocator::Unmap(BufferHandle &handle)
{
if (handle.virAddr == nullptr) {
DISPLAY_LOGE("virAddr is nullptr , has not map the buffer");
return DISPLAY_PARAM_ERR;
}
int ret = munmap(handle.virAddr, handle.size);
if (ret != 0) {
DISPLAY_LOGE("munmap failed err: %{public}d", errno);
return DISPLAY_FAILURE;
}
handle.virAddr = nullptr;
return DISPLAY_SUCCESS;
}
}
}
}