220 lines
8.3 KiB
C++
220 lines
8.3 KiB
C++
/*
|
|
* 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 <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <sys/epoll.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <wayland-client.h>
|
|
#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<WaylandDmaBuffer*>(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<WaylandDmaBuffer*>(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;
|
|
} |