/* * Copyright (C) 2021 Amlogic Corporation. * * 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 #include #include #include #include #include #include #include #include #include "wayland_shm.h" #include "Logger.h" #include "wayland_display.h" #include "ErrorCode.h" #include "Utils.h" #include "wayland_videoformat.h" #define TAG "rlib:wayland_shm" WaylandShmBuffer::WaylandShmBuffer(WaylandDisplay *display, int logCategory) { mDisplay = display; mWlBuffer = NULL; mStride = 0; mData = NULL; mSize = 0; mWidth = 0; mHeight = 0; mFormat = VIDEO_FORMAT_UNKNOWN; mLogCategory = logCategory; } WaylandShmBuffer::~WaylandShmBuffer() { if (mWlBuffer) { wl_buffer_destroy(mWlBuffer); mWlBuffer = NULL; } if (mData) { munmap(mData, mSize); mData = NULL; } } struct wl_buffer *WaylandShmBuffer::constructAreaShmWlBuffer(int width, int height, RenderVideoFormat format) { struct wl_shm_pool *pool = NULL; int fd = -1; int ret = 0; mWidth = width; mHeight = height; mFormat = format; switch (format) { case VIDEO_FORMAT_YUY2: case VIDEO_FORMAT_YVYU: case VIDEO_FORMAT_UYVY: case VIDEO_FORMAT_VYUY: { mStride = ROUND_UP_4 (width * 2); mSize = mStride * height; } break; case VIDEO_FORMAT_AYUV: case VIDEO_FORMAT_RGBx: case VIDEO_FORMAT_RGBA: case VIDEO_FORMAT_BGRA: case VIDEO_FORMAT_xRGB: case VIDEO_FORMAT_ARGB: case VIDEO_FORMAT_xBGR: case VIDEO_FORMAT_ABGR: case VIDEO_FORMAT_r210: case VIDEO_FORMAT_Y410: case VIDEO_FORMAT_VUYA: case VIDEO_FORMAT_BGR10A2_LE: case VIDEO_FORMAT_BGRx: { mStride = width * 4; mSize = mStride * height; } break; default: break; } if (mStride <= 0 || mSize <= 0) { WARNING(mLogCategory,"Unsupport format"); goto tag_err; } fd = createAnonymousFile(mSize); if (fd < 0) { ERROR(mLogCategory,"create anonymous file fail"); return NULL; } mData = mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mData == MAP_FAILED) { ERROR(mLogCategory,"mmap failed: %s",strerror(errno)); mData = NULL; goto tag_err; } //init buffer data,set alpha transparent memset(mData, 0x00, mSize); if (mDisplay->getShm() == NULL) { ERROR(mLogCategory,"Shm is null"); goto tag_err; } uint32_t shmFormat; ret = mDisplay->toShmBufferFormat(format, &shmFormat); if (ret != NO_ERROR) { ERROR(mLogCategory,"video format to shm format fail"); goto tag_err; } pool = wl_shm_create_pool(mDisplay->getShm(), fd, mSize); mWlBuffer = wl_shm_pool_create_buffer(pool, 0, width, height, mStride, shmFormat); wl_shm_pool_destroy(pool); close(fd); fd = -1; return mWlBuffer; tag_err: if (fd > 0) { close(fd); fd = -1; } return NULL; } /** * @brief request shm memory buffer. only support 1 plane * * @param buffer * @param format * @return struct wl_buffer* */ struct wl_buffer *WaylandShmBuffer::constructVideoWlBuffer(RenderBuffer *buffer, RenderVideoFormat format) { struct wl_shm_pool *pool = NULL; uint32_t shmFormat; int ret; int fd = -1; ret = mDisplay->toShmBufferFormat(format, &shmFormat); if (ret != NO_ERROR) { ERROR(mLogCategory,"Error change render video format to dmabuffer format fail"); return NULL; } mFormat = format; mWidth = buffer->dma.width; mHeight = buffer->dma.height; mStride = buffer->dma.stride[0]; mSize = buffer->dma.size[0]; mOffset = buffer->dma.offset[0]; fd = buffer->dma.fd[0]; TRACE(mLogCategory,"shm buf %s,fd:%d,stride:%d,size:%d (%dx%d)",print_shm_format_name(shmFormat), fd, mStride, mSize, mWidth, mHeight); pool = wl_shm_create_pool(mDisplay->getShm(), fd, mSize); if (pool) { mWlBuffer = wl_shm_pool_create_buffer(pool, mOffset, mWidth, mHeight, mStride, shmFormat); wl_shm_pool_destroy(pool); } return mWlBuffer; } int WaylandShmBuffer::createAnonymousFile(off_t size) { char filename[1024]; const char *path; static int init = 0; int fd = -1; int ret; path = getenv("XDG_RUNTIME_DIR"); if (!path) { WARNING(mLogCategory,"not set XDG_RUNTIME_DIR env"); goto tag_err; } /* allocate shm pool */ snprintf (filename, 1024, "%s/%s-%d-%s", path, "wayland-shm", init++, "XXXXXX"); fd = mkstemp(filename); if (fd < 0) { ERROR(mLogCategory,"make anonymous file fail"); goto tag_err; } unlink(filename); //set cloexec { long flags; flags = fcntl(fd, F_GETFD); if (flags == -1) goto tag_err; if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) goto tag_err; } do { ret = ftruncate(fd, size); } while (ret < 0 && errno == EINTR); if (ret < 0) { goto tag_err; } return fd; tag_err: if (fd > 0) { close(fd); fd = -1; } return -1; }