498 lines
15 KiB
C++
Executable File
498 lines
15 KiB
C++
Executable File
/*
|
|
* Copyright 2019 Rockchip Electronics 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.
|
|
*
|
|
* author: rimon.xu@rock-chips.com
|
|
* date: 2019/12/31
|
|
* module: sideband window
|
|
*/
|
|
|
|
// #define LOG_NDEBUG 0
|
|
#define LOG_TAG "RTSidebandWindow"
|
|
|
|
#include "log/log.h"
|
|
#include <sys/time.h>
|
|
#include <utils/Timers.h>
|
|
#include <string.h>
|
|
#include <ui/GraphicBufferAllocator.h>
|
|
#include <ui/GraphicBufferMapper.h>
|
|
|
|
#include "RTSidebandWindow.h"
|
|
#include "video_tunnel.h"
|
|
|
|
namespace android {
|
|
|
|
#define FUNCTION_IN() ALOGV("%s %d in", __FUNCTION__, __LINE__)
|
|
|
|
#define MIN_BUFFER_COUNT_UNDEQUEUE 2
|
|
#define MALI_GRALLOC_USAGE_NO_AFBC 0x20000000U
|
|
|
|
static uint64_t g_session_id;
|
|
|
|
#if HAVE_VDPP
|
|
static int gsFrameCcount = 0;
|
|
static void debugShowFPS()
|
|
{
|
|
static int mFrameCount;
|
|
static int mLastFrameCount = 0;
|
|
static nsecs_t mLastFpsTime = 0;
|
|
static float mFps = 0;
|
|
|
|
mFrameCount++;
|
|
nsecs_t now = systemTime();
|
|
nsecs_t diff = now - mLastFpsTime;
|
|
if (diff > ms2ns(500)) {
|
|
mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
|
|
mLastFpsTime = now;
|
|
mLastFrameCount = mFrameCount;
|
|
ALOGD("mFrameCount = %d mFps = %2.3f",mFrameCount, mFps);
|
|
}
|
|
}
|
|
|
|
static vdpp_buffer_handle* get_vdpp_buffer(struct vdpp_dev* mVdppDev, vt_buffer_t *buffer, int mVTID) {
|
|
struct vdpp_buffer_handle* vdppBuffer = NULL;
|
|
|
|
if (vdpp_access(mVdppDev, buffer)) {
|
|
mVdppDev->tunnel_id = mVTID;
|
|
vdpp_dev_init(mVdppDev, buffer->handle);
|
|
vdppBuffer = vdpp_get_unused_buf(mVdppDev);
|
|
}
|
|
|
|
return vdppBuffer;
|
|
}
|
|
#endif
|
|
|
|
RTSidebandWindow::RTSidebandWindow()
|
|
: mVTDevFd(-1),
|
|
mVTID(-1),
|
|
mBufferCnt(0),
|
|
mVTunnelErr(false),
|
|
mRenderingCnt(0) {
|
|
FUNCTION_IN();
|
|
|
|
memset(&mWinAttr, 0, sizeof(vt_win_attr_t));
|
|
}
|
|
|
|
RTSidebandWindow::~RTSidebandWindow() {
|
|
FUNCTION_IN();
|
|
}
|
|
|
|
status_t RTSidebandWindow::init(const vt_win_attr_t *attr) {
|
|
FUNCTION_IN();
|
|
status_t err = 0;
|
|
|
|
if (attr->struct_size != sizeof(vt_win_attr_t)) {
|
|
ALOGE("init: sideband window info struct size is invailed!");
|
|
goto __FAILED;
|
|
}
|
|
|
|
memcpy(&mWinAttr, attr, sizeof(vt_win_attr_t));
|
|
|
|
mVTDevFd = rk_vt_open();
|
|
if (mVTDevFd < 0) {
|
|
goto __FAILED;
|
|
}
|
|
err = rk_vt_alloc_id(mVTDevFd, &mVTID);
|
|
if (err < 0 || mVTID < 0) {
|
|
goto __ALLOC_ID_FAILED;
|
|
}
|
|
err = rk_vt_connect(mVTDevFd, mVTID, RKVT_ROLE_PRODUCER);
|
|
if (err < 0) {
|
|
goto __CONNECT_FALED;
|
|
}
|
|
|
|
#if HAVE_VDPP
|
|
mVdppDev = (struct vdpp_dev*)calloc(sizeof(struct vdpp_dev), 1);
|
|
if (mVdppDev)
|
|
vdpp_create_ctx(mVdppDev);
|
|
#endif
|
|
|
|
return 0;
|
|
__CONNECT_FALED:
|
|
rk_vt_free_id(mVTDevFd, mVTID);
|
|
__ALLOC_ID_FAILED:
|
|
rk_vt_close(mVTDevFd);
|
|
__FAILED:
|
|
return -1;
|
|
}
|
|
|
|
status_t RTSidebandWindow::release() {
|
|
FUNCTION_IN();
|
|
|
|
if (mVTID >= 0) {
|
|
rk_vt_reset(mVTDevFd, mVTID);
|
|
rk_vt_disconnect(mVTDevFd, mVTID, RKVT_ROLE_PRODUCER);
|
|
rk_vt_free_id(mVTDevFd, mVTID);
|
|
rk_vt_close(mVTDevFd);
|
|
}
|
|
do {
|
|
android::Mutex::Autolock _l(mLock);
|
|
while (mBufferQueue.size() > 0) {
|
|
vt_buffer_t *tmpBuffer = mBufferQueue.front();
|
|
mBufferQueue.erase(mBufferQueue.begin());
|
|
freeBuffer(&tmpBuffer);
|
|
}
|
|
} while (0);
|
|
mRenderingCnt = 0;
|
|
|
|
#if HAVE_VDPP
|
|
{
|
|
android::Mutex::Autolock _l(mVdppLock);
|
|
mVdppReplaceQueue.clear();
|
|
mVdppRenderingQueue.clear();
|
|
if (mVdppDev) {
|
|
vdpp_destroy_ctx(mVdppDev);
|
|
pthread_mutex_destroy(&mVdppDev->vdppLock);
|
|
free(mVdppDev);
|
|
mVdppDev = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::start() {
|
|
FUNCTION_IN();
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::stop() {
|
|
FUNCTION_IN();
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::flush() {
|
|
FUNCTION_IN();
|
|
#if HAVE_VDPP
|
|
{
|
|
android::Mutex::Autolock _l(mVdppLock);
|
|
std::list<struct vdpp_buffer_handle *>::iterator it;
|
|
for (it = mVdppRenderingQueue.begin(); it != mVdppRenderingQueue.end(); it++) {
|
|
struct vdpp_buffer_handle *hdl = *it;
|
|
hdl->used = false;
|
|
mVdppRenderingQueue.erase(it);
|
|
}
|
|
mVdppReplaceQueue.clear();
|
|
}
|
|
#endif
|
|
|
|
android::Mutex::Autolock _l(mLock);
|
|
while (mBufferQueue.size() > 0) {
|
|
vt_buffer_t *tmpBuffer = mBufferQueue.front();
|
|
mBufferQueue.erase(mBufferQueue.begin());
|
|
freeBuffer(&tmpBuffer);
|
|
}
|
|
mRenderingCnt = 0;
|
|
|
|
return rk_vt_reset(mVTDevFd, mVTID);
|
|
}
|
|
|
|
status_t RTSidebandWindow::setAttr(const vt_win_attr_t *attr) {
|
|
FUNCTION_IN();
|
|
android::Mutex::Autolock _l(mLock);
|
|
|
|
if (attr->struct_size != sizeof(vt_win_attr_t)) {
|
|
ALOGE("setAttr: sideband window info struct size is invailed!");
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&mWinAttr, attr, sizeof(vt_win_attr_t));
|
|
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::getAttr(vt_win_attr_t *info) {
|
|
FUNCTION_IN();
|
|
android::Mutex::Autolock _l(mLock);
|
|
|
|
memcpy(info, &mWinAttr, sizeof(vt_win_attr_t));
|
|
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::allocateSidebandHandle(buffer_handle_t *handle) {
|
|
FUNCTION_IN();
|
|
native_handle_t *temp_buffer = NULL;
|
|
vt_sideband_data_t info;
|
|
|
|
memset(&info, 0, sizeof(vt_sideband_data_t));
|
|
|
|
g_session_id++;
|
|
info.version = sizeof(vt_sideband_data_t);
|
|
info.tunnel_id = mVTID;
|
|
info.crop.left = mWinAttr.left;
|
|
info.crop.top = mWinAttr.top;
|
|
info.crop.right = mWinAttr.right;
|
|
info.crop.bottom = mWinAttr.bottom;
|
|
info.width = mWinAttr.width;
|
|
info.height = mWinAttr.height;
|
|
info.format = mWinAttr.format;
|
|
info.transform = mWinAttr.transform;
|
|
info.usage = mWinAttr.usage;
|
|
info.data_space = mWinAttr.data_space;
|
|
info.compress_mode = mWinAttr.compress_mode;
|
|
info.session_id = g_session_id;
|
|
|
|
temp_buffer = native_handle_create(0, sizeof(vt_sideband_data_t) / sizeof(int));
|
|
temp_buffer->version = sizeof(native_handle_t);
|
|
temp_buffer->numFds = 0;
|
|
temp_buffer->numInts = sizeof(vt_sideband_data_t) / sizeof(int);
|
|
memcpy(&temp_buffer->data[0], &info, sizeof(vt_sideband_data_t));
|
|
|
|
*handle = (buffer_handle_t)temp_buffer;
|
|
|
|
ALOGI("allocate handle %p to native window session-id %lld",
|
|
temp_buffer, (long long)info.session_id);
|
|
ALOGI("allocate handle: tid[%d] crop[%d %d %d %d], wxh[%d %d] fmt[%d] " \
|
|
"transform[%d] usage[%p] data_space[%lld] compress_mode[%d]",
|
|
info.tunnel_id, info.crop.left, info.crop.top, info.crop.right,
|
|
info.crop.bottom, info.width, info.height, info.format, info.transform,
|
|
(void *)info.usage, (long long)info.data_space, info.compress_mode);
|
|
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::allocateBuffer(vt_buffer_t **buffer) {
|
|
FUNCTION_IN();
|
|
GraphicBufferAllocator &allocator = GraphicBufferAllocator::get();
|
|
buffer_handle_t tempBuffer = NULL;
|
|
uint32_t outStride = 0;
|
|
vt_buffer_t *vtBuffer = NULL;
|
|
status_t err = 0;
|
|
ANativeWindowBuffer *nativeWinBuf = NULL;
|
|
ANativeWindow *nativeWindow = (ANativeWindow *)mWinAttr.native_window;
|
|
|
|
if (nativeWindow) {
|
|
err = native_window_dequeue_buffer_and_wait(nativeWindow, &nativeWinBuf);
|
|
if (err != NO_ERROR) {
|
|
return err;
|
|
}
|
|
|
|
vtBuffer = rk_vt_buffer_malloc();
|
|
vtBuffer->handle = (native_handle_t *)nativeWinBuf->handle;
|
|
vtBuffer->buffer_mode = RKVT_BUFFER_EXTERNAL;
|
|
vtBuffer->private_data = (int64_t)nativeWinBuf;
|
|
} else {
|
|
err = allocator.allocate(mWinAttr.width,
|
|
mWinAttr.height,
|
|
mWinAttr.format,
|
|
1,
|
|
mWinAttr.usage,
|
|
&tempBuffer,
|
|
&outStride,
|
|
0,
|
|
std::move("videotunnel"));
|
|
if (err != NO_ERROR) {
|
|
return err;
|
|
}
|
|
|
|
vtBuffer = rk_vt_buffer_malloc();
|
|
vtBuffer->handle = (native_handle_t *)tempBuffer;
|
|
}
|
|
*buffer = vtBuffer;
|
|
ALOGI("allocate buffer: fd-0[%d] wxh[%d %d] fmt[0x%x] usage[%p] mode[%s] priv[%p]",
|
|
vtBuffer->handle->data[0], mWinAttr.width, mWinAttr.height,
|
|
mWinAttr.format, (void *)mWinAttr.usage,
|
|
vtBuffer->buffer_mode == RKVT_BUFFER_INTERNAL ? "internal" : "external",
|
|
(void *)vtBuffer->private_data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::freeBuffer(vt_buffer_t **buffer) {
|
|
FUNCTION_IN();
|
|
GraphicBufferAllocator &allocator = GraphicBufferAllocator::get();
|
|
ANativeWindow *nativeWindow = (ANativeWindow *)mWinAttr.native_window;
|
|
|
|
ALOGI("free buffer: fd-0[%d] wxh[%d %d] fmt[0x%x] usage[%p]",
|
|
(*buffer)->handle->data[0], mWinAttr.width, mWinAttr.height,
|
|
mWinAttr.format, (void *)mWinAttr.usage);
|
|
if (nativeWindow && (*buffer)->private_data) {
|
|
nativeWindow->cancelBuffer(nativeWindow,
|
|
(ANativeWindowBuffer *)((*buffer)->private_data), -1);
|
|
} else {
|
|
allocator.free((*buffer)->handle);
|
|
}
|
|
(*buffer)->handle = NULL;
|
|
rk_vt_buffer_free(buffer);
|
|
*buffer = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
vt_buffer_t* RTSidebandWindow::getSidebandOriginalBuffer(vt_buffer_t *buffer) {
|
|
struct vdpp_buffer_handle* outVdppHdl = NULL;
|
|
vt_buffer_t *tmpBuffer = NULL;
|
|
bool found = false;
|
|
|
|
#if HAVE_VDPP
|
|
android::Mutex::Autolock _Vdppl(mVdppLock);
|
|
for (auto it = mVdppRenderingQueue.begin(); it != mVdppRenderingQueue.end(); it++) {
|
|
struct vdpp_buffer_handle* outVdppHdl = *it;
|
|
if (outVdppHdl && outVdppHdl->vtBuffer == buffer) {
|
|
outVdppHdl->used = false;
|
|
mVdppRenderingQueue.erase(it);
|
|
outVdppHdl = NULL;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
if (mVdppReplaceQueue.size()) {
|
|
tmpBuffer = mVdppReplaceQueue.front();
|
|
mVdppReplaceQueue.pop_front();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return tmpBuffer;
|
|
}
|
|
|
|
vt_buffer_t* RTSidebandWindow::findVtBufferByNativeWindow(
|
|
ANativeWindowBuffer *nativeWinBuf) {
|
|
vt_buffer_t *vtBuf = NULL;
|
|
|
|
for (auto it : mBufferQueue) {
|
|
if (it->private_data == (int64_t)nativeWinBuf) {
|
|
vtBuf = it;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return vtBuf;
|
|
}
|
|
|
|
status_t RTSidebandWindow::dequeueBuffer(vt_buffer_t **buffer, int timeout_ms, int *fence) {
|
|
FUNCTION_IN();
|
|
int err = 0;
|
|
vt_buffer_t *tmpBuffer = NULL;
|
|
ANativeWindowBuffer *nativeWinBuf = NULL;
|
|
ANativeWindow *nativeWindow = (ANativeWindow *)mWinAttr.native_window;
|
|
|
|
{
|
|
android::Mutex::Autolock _l(mLock);
|
|
if (mBufferQueue.size() < mWinAttr.buffer_cnt) {
|
|
err = allocateBuffer(buffer);
|
|
if (err == 0) {
|
|
mBufferQueue.push_back(*buffer);
|
|
}
|
|
return err;
|
|
}
|
|
}
|
|
|
|
if (nativeWindow && mVTunnelErr) {
|
|
err = native_window_dequeue_buffer_and_wait(nativeWindow, &nativeWinBuf);
|
|
tmpBuffer = findVtBufferByNativeWindow(nativeWinBuf);
|
|
} else {
|
|
err = rk_vt_dequeue_buffer(mVTDevFd, mVTID, timeout_ms, &tmpBuffer);
|
|
}
|
|
if (err != 0 && tmpBuffer == NULL) {
|
|
return err;
|
|
}
|
|
|
|
#if HAVE_VDPP
|
|
vdpp_update_disp_rect(mVdppDev, tmpBuffer);
|
|
vt_buffer_t *mSideBandBuffer = getSidebandOriginalBuffer(tmpBuffer);
|
|
if (mSideBandBuffer)
|
|
tmpBuffer = mSideBandBuffer;
|
|
mRenderingCnt--;
|
|
#endif
|
|
*buffer = tmpBuffer;
|
|
*fence = -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
status_t RTSidebandWindow::queueBuffer(vt_buffer_t *buffer, int fence, int64_t expected_present_time) {
|
|
FUNCTION_IN();
|
|
struct vdpp_buffer_handle* outVdppHdl = NULL;
|
|
ANativeWindow *nativeWindow = (ANativeWindow *)mWinAttr.native_window;
|
|
|
|
mRenderingCnt++;
|
|
buffer->crop.left = mWinAttr.left;
|
|
buffer->crop.top = mWinAttr.top;
|
|
buffer->crop.right = mWinAttr.right;
|
|
buffer->crop.bottom = mWinAttr.bottom;
|
|
|
|
#if HAVE_VDPP
|
|
outVdppHdl = get_vdpp_buffer(mVdppDev, buffer, mVTID);
|
|
if (outVdppHdl) {
|
|
vdpp_process_frame(mVdppDev, buffer, outVdppHdl->vtBuffer);
|
|
outVdppHdl->vtBuffer->crop.left = 0;
|
|
outVdppHdl->vtBuffer->crop.top = 0;
|
|
outVdppHdl->vtBuffer->crop.right = mVdppDev->disp_rect.right;
|
|
outVdppHdl->vtBuffer->crop.bottom = mVdppDev->disp_rect.bottom;
|
|
android::Mutex::Autolock _Vdppl(mVdppLock);
|
|
mVdppRenderingQueue.push_back(outVdppHdl);
|
|
mVdppReplaceQueue.push_back(buffer);
|
|
buffer = outVdppHdl->vtBuffer;
|
|
debugShowFPS();
|
|
}
|
|
#endif
|
|
if (nativeWindow && !mVTunnelErr && buffer->private_data) {
|
|
if (!rk_vt_query_has_consumer(mVTDevFd, mVTID)) {
|
|
ALOGW("can't find consumer, change to queue surfaceflinger.");
|
|
mVTunnelErr = true;
|
|
native_window_set_sideband_stream(nativeWindow, NULL);
|
|
}
|
|
}
|
|
if (nativeWindow && mVTunnelErr && buffer->private_data) {
|
|
return nativeWindow->queueBuffer(nativeWindow,
|
|
(ANativeWindowBuffer *)(buffer->private_data), -1);
|
|
} else {
|
|
return rk_vt_queue_buffer(mVTDevFd, mVTID, (vt_buffer_t *)buffer, expected_present_time);
|
|
}
|
|
}
|
|
|
|
status_t RTSidebandWindow::cancelBuffer(vt_buffer_t *buffer) {
|
|
FUNCTION_IN();
|
|
struct vdpp_buffer_handle* vdppBuffer = NULL;
|
|
ANativeWindow *nativeWindow = (ANativeWindow *)mWinAttr.native_window;
|
|
|
|
{
|
|
android::Mutex::Autolock _l(mLock);
|
|
if (mRenderingCnt >= mWinAttr.remain_cnt) {
|
|
for (auto it = mBufferQueue.begin(); it != mBufferQueue.end(); it++) {
|
|
if (*it == buffer) {
|
|
mBufferQueue.erase(it);
|
|
return freeBuffer(&buffer);
|
|
}
|
|
}
|
|
ALOGW("cancel buffer(%p) fd-0(%d) not allocate by sideband window.",
|
|
buffer, buffer->handle->data[0]);
|
|
}
|
|
}
|
|
mRenderingCnt++;
|
|
|
|
#if HAVE_VDPP
|
|
vdppBuffer = get_vdpp_buffer(mVdppDev, buffer, mVTID);
|
|
if (vdppBuffer) {
|
|
android::Mutex::Autolock _Vdppl(mVdppLock);
|
|
mVdppRenderingQueue.push_back(vdppBuffer);
|
|
mVdppReplaceQueue.push_back(buffer);
|
|
buffer = vdppBuffer->vtBuffer;
|
|
}
|
|
#endif
|
|
|
|
if (nativeWindow && mVTunnelErr && buffer->private_data) {
|
|
return nativeWindow->cancelBuffer(nativeWindow,
|
|
(ANativeWindowBuffer *)(buffer->private_data), -1);
|
|
} else {
|
|
return rk_vt_cancel_buffer(mVTDevFd, mVTID, buffer);
|
|
}
|
|
}
|
|
|
|
}
|