/* * 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 "xdg-shell-client-protocol.h" #include "viewporter-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "fullscreen-shell-unstable-v1-client-protocol.h" #include "wayland_dma.h" #include "Logger.h" #include "wayland_display.h" #include "ErrorCode.h" #include "wayland_videoformat.h" #include "Utils.h" #define TAG "rlib:wayland_dma" WaylandDmaBuffer::WaylandDmaBuffer(WaylandDisplay *display, int logCategory) : mDisplay(display), mLogCategory(logCategory) { mRenderDmaBuffer = {0,}; mWlBuffer = NULL; mData = NULL; mSize = 0; mReady.store(false, std::memory_order_release); } WaylandDmaBuffer::~WaylandDmaBuffer() { //waiting callback for zwp buffer if (mReady.load(std::memory_order_acquire)) { int cnt = 1; { WARNING(mLogCategory,"waiting zwp buffer,signal"); ATools::Mutex::Autolock _l(mMutex); mCondition.signal(); } do { //waiting 10ms usleep(1*1000); //1ms ++cnt; if (cnt > 10) { ERROR(mLogCategory,"zwp buffer callback do not response"); } } while (mReady.load(std::memory_order_acquire) && cnt <= 10); } //release wl_buffer if (mWlBuffer) { // TRACE(mLogCategory,"delete WaylandDmaBuffer:%p,wl_buffer:%p %dx%d", // this,mWlBuffer,mRenderDmaBuffer.width,mRenderDmaBuffer.height); wl_buffer_destroy(mWlBuffer); mWlBuffer = NULL; } mReady.store(false, std::memory_order_release); mDisplay = NULL; } void WaylandDmaBuffer::dmabufCreateSuccess(void *data, struct zwp_linux_buffer_params_v1 *params, struct wl_buffer *new_buffer) { WaylandDmaBuffer *waylandDma = static_cast(data); // TRACE(waylandDma->mLogCategory,"++create dma wl_buffer:%p ",new_buffer); if (waylandDma && waylandDma->mReady.load(std::memory_order_acquire)) { ATools::Mutex::Autolock _l(waylandDma->mMutex); waylandDma->mWlBuffer = new_buffer; waylandDma->mCondition.signal(); } else { wl_buffer_destroy(new_buffer); } } void WaylandDmaBuffer::dmabufCreateFail(void *data, struct zwp_linux_buffer_params_v1 *params) { WaylandDmaBuffer *waylandDma = static_cast(data); if (waylandDma && waylandDma->mReady.load(std::memory_order_acquire)) { ATools::Mutex::Autolock _l(waylandDma->mMutex); ERROR(waylandDma->mLogCategory,"Error,create wl_buffer fail"); waylandDma->mWlBuffer = NULL; waylandDma->mCondition.signal(); } } static const struct zwp_linux_buffer_params_v1_listener dmabuf_params_listener = { WaylandDmaBuffer::dmabufCreateSuccess, WaylandDmaBuffer::dmabufCreateFail }; struct wl_buffer *WaylandDmaBuffer::constructWlBuffer(RenderDmaBuffer *dmabuf, RenderVideoFormat format) { struct zwp_linux_buffer_params_v1 *params = NULL; int ret = NO_ERROR; uint64_t formatModifier = 0; uint32_t flags = 0; uint32_t dmabufferFormat = 0; struct aml_config* amlConfig = mDisplay->getAmlConfig(); WaylandDisplay::AmlConfigAPIList *amlConfigAPI = mDisplay->getAmlConfigAPIList(); /*if wlBuffer created or waiting creation wlBuffer,return*/ if (mWlBuffer) { return mWlBuffer; } /*waiting create zwp buffer response*/ if (mReady.load(std::memory_order_acquire)) { return NULL; } ret = mDisplay->toDmaBufferFormat(format, &dmabufferFormat, &formatModifier); if (ret != NO_ERROR) { ERROR(mLogCategory,"Error change render video format to dmabuffer format fail"); return NULL; } //check dma buffer if (dmabuf->planeCnt < 0) { ERROR(mLogCategory,"Error dmabuf plane count is 0"); return NULL; } for (int i = 0; i < dmabuf->planeCnt; i++) { if (dmabuf->fd[i] <= 0) { ERROR(mLogCategory,"Error dmabuf plane fd is 0"); return NULL; } } memcpy(&mRenderDmaBuffer, dmabuf, sizeof(RenderDmaBuffer)); if (!mDisplay->getWlDisplay()) { WARNING(mLogCategory, "Error,disconnected from weston"); return NULL; } params = zwp_linux_dmabuf_v1_create_params (mDisplay->getDmaBuf()); if (!params) { ERROR(mLogCategory, "Error zwp_linux_dmabuf_v1_create_params fail"); return NULL; } //told weston to use direct display for video plane or osd display if (mDisplay->getWlDirectDisplay()) { if (amlConfig && mDisplay->isVideoOnOSD() && amlConfigAPI->enableVideoOnOSD) { //to osd DEBUG(mLogCategory,"aml_config_render_to_osd"); aml_config_render_to_osd(amlConfig, params); } else { //to video plane DEBUG(mLogCategory,"weston_direct_display_v1_enable"); weston_direct_display_v1_enable(mDisplay->getWlDirectDisplay(), params); } } for (int i = 0; i < dmabuf->planeCnt; i++) { TRACE(mLogCategory,"dma buf index:%d,fd:%d,stride:%d,offset:%d",i, dmabuf->fd[i],dmabuf->stride[i], dmabuf->offset[i]); if (!amlConfigAPI->enableNeedOriginalSize) { //normal playback zwp_linux_buffer_params_v1_add(params, dmabuf->fd[i], i, /*plane_idx*/ dmabuf->offset[i], /*data offset*/ dmabuf->stride[i], formatModifier >> 32, formatModifier & 0xffffffff); } else { //weston requests origin video frame size nor dma buffer frame size zwp_linux_buffer_params_v1_add(params, dmabuf->fd[i], i, /*plane_idx*/ dmabuf->offset[i], /*data offset*/ ROUND_UP_32(mDisplay->getFrameWidth()), /*use origin video frame size (aligned with 32bit) to pass drm size check*/ formatModifier >> 32, formatModifier & 0xffffffff); } } mReady.store(true, std::memory_order_release); /* Request buffer creation */ zwp_linux_buffer_params_v1_add_listener (params, &dmabuf_params_listener, (void *)this); if (!amlConfigAPI->enableNeedOriginalSize) { //normal playback DEBUG(mLogCategory,"zwp_linux_buffer_params_v1_create,dma width:%d,height:%d,dmabufferformat:%d",dmabuf->width,dmabuf->height,dmabufferFormat); zwp_linux_buffer_params_v1_create (params, dmabuf->width, dmabuf->height, dmabufferFormat, flags); } else { //weston requests origin video frame size nor dma buffer frame size DEBUG(mLogCategory,"zwp_linux_buffer_params_v1_create,origin width:%d,height:%d,dmabufferformat:%d",mDisplay->getFrameWidth(),mDisplay->getFrameHeight(),dmabufferFormat); zwp_linux_buffer_params_v1_create (params, mDisplay->getFrameWidth(), mDisplay->getFrameHeight(), dmabufferFormat, flags); } /* Wait for the request answer */ wl_display_flush (mDisplay->getWlDisplay()); ATools::Mutex::Autolock _l(mMutex); if (!mWlBuffer) { //if this wlbuffer had created,don't wait zwp linux buffer callback mWlBuffer =(struct wl_buffer *)0xffffffff; while (mWlBuffer == (struct wl_buffer *)0xffffffff) { //try wait for 1000 ms if (ERROR_TIMED_OUT == mCondition.waitRelative(mMutex, 1000/*ms*/)) { WARNING(mLogCategory,"zwp_linux_buffer_params_v1_create timeout"); mWlBuffer = NULL; } } } mReady.store(false, std::memory_order_release); //destroy zwp linux buffer params zwp_linux_buffer_params_v1_destroy (params); //flush event to weston wl_display_flush (mDisplay->getWlDisplay()); return mWlBuffer; }