blob: b02e17b29ab73971ba1f1a0e9de33bba7f4480a2 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
* Copyright@ Samsung 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.
*/
/*!
* \file libscaler.cpp
* \brief source file for Scaler HAL
* \author Sunyoung Kang (sy0816.kang@samsung.com)
* \date 2013/02/01
*
* <b>Revision History: </b>
* - 2013.02.01 : Sunyoung Kang (sy0816.kang@samsung.com) \n
* Create
* - 2013.04.10 : Cho KyongHo (pullip.cho@samsung.com) \n
* Refactoring
*
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <system/graphics.h>
#define LOG_TAG "libexynosscaler"
#include <log/log.h>
#include <cerrno>
#include <cstring>
#include <hardware/exynos/acryl.h>
#include "exynos_scaler.h"
#define ARRSIZE(arr) (sizeof(arr)/sizeof(arr[0]))
class CScalerAcryl {
Acrylic *mAcrylicHandle = nullptr;
AcrylicLayer *mLayer = nullptr;
bool mDRM;
int mColorSpace;
int mTransform;
int mFilter;
int mFramerate;
struct frameInfo {
hwc_rect_t rect;
size_t len[SC_NUM_OF_PLANES];
int num_buffers;
} mSrcInfo, mDstInfo;
bool SetFormat(frameInfo &info, unsigned int width, unsigned int height, unsigned int v4l2_fmt, bool isSrc);
inline void SetCrop(hwc_rect_t &rect, unsigned int l, unsigned int t, unsigned int w, unsigned int h) {
rect.left = l;
rect.top = t;
rect.right = l + w;
rect.bottom = t + h;
}
inline size_t GetPlaneSize(frameInfo &info, unsigned int plane_num) {
return info.len[plane_num];
}
public:
CScalerAcryl();
~CScalerAcryl();
Acrylic *getHandle() { return mAcrylicHandle; }
AcrylicLayer *getLayer() { return mLayer; }
inline bool Valid() { return mAcrylicHandle != nullptr; }
bool SetRotate(int rot, int hflip, int vflip);
inline void SetFilter(unsigned int filter) {
/* TODO */
mFilter = filter;
}
inline void SetFrameRate(int framerate) {
/* TODO */
mFramerate = framerate;
}
inline void SetCSCEq(unsigned int colorspace) {
mColorSpace = colorspace;
}
inline int GetCSCEq(void) {
return mColorSpace;
}
inline void SetDRM(bool drm) {
mDRM = drm;
}
inline bool GetDRM(void) {
return mDRM;
}
inline void SetSrcCrop(unsigned int l, unsigned int t, unsigned int w, unsigned int h) {
SetCrop(mSrcInfo.rect, l, t, w, h);
}
inline void SetDstCrop(unsigned int l, unsigned int t, unsigned int w, unsigned int h) {
SetCrop(mDstInfo.rect, l, t, w, h);
}
inline hwc_rect_t& GetSrcCrop(void) { return mSrcInfo.rect; }
inline hwc_rect_t& GetDstCrop(void) { return mDstInfo.rect; }
inline bool SetSrcInfo(unsigned int width, unsigned int height, unsigned int v4l2_fmt) {
return SetFormat(mSrcInfo, width, height, v4l2_fmt, true);
}
inline bool SetDstInfo(unsigned int width, unsigned int height, unsigned int v4l2_fmt) {
return SetFormat(mDstInfo, width, height, v4l2_fmt, false);
}
inline size_t GetSrcPlaneSize(unsigned int plane_num) {
return GetPlaneSize(mSrcInfo, plane_num);
}
inline size_t GetDstPlaneSize(unsigned int plane_num) {
return GetPlaneSize(mDstInfo, plane_num);
}
inline int GetSrcPlaneCount(void) {
return mSrcInfo.num_buffers;
}
inline int GetDstPlaneCount(void) {
return mDstInfo.num_buffers;
}
inline int GetTransform(void) {
return mTransform;
}
};
#define V4L2_PIX_FMT_ABGR2101010 v4l2_fourcc('A', 'R', '1', '0')
#define V4L2_PIX_FMT_NV12N v4l2_fourcc('N', 'N', '1', '2')
#define V4L2_PIX_FMT_NV12NT v4l2_fourcc('T', 'N', '1', '2')
#define V4L2_PIX_FMT_YUV420N v4l2_fourcc('Y', 'N', '1', '2')
#define V4L2_PIX_FMT_NV12N_10B v4l2_fourcc('B', 'N', '1', '2')
const int v4l2_to_hal_format_table[][2] = {
{ V4L2_PIX_FMT_RGB32, HAL_PIXEL_FORMAT_RGBA_8888 },
{ V4L2_PIX_FMT_RGB24, HAL_PIXEL_FORMAT_RGB_888 },
{ V4L2_PIX_FMT_RGB565, HAL_PIXEL_FORMAT_RGB_565 },
{ V4L2_PIX_FMT_BGR32, HAL_PIXEL_FORMAT_BGRA_8888 },
{ V4L2_PIX_FMT_ABGR2101010, HAL_PIXEL_FORMAT_RGBA_1010102, },
{ V4L2_PIX_FMT_YVU420M, HAL_PIXEL_FORMAT_EXYNOS_YV12_M },
{ V4L2_PIX_FMT_YUV420M, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M },
{ V4L2_PIX_FMT_YVU420, HAL_PIXEL_FORMAT_YV12 },
{ V4L2_PIX_FMT_YUV420, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P },
{ V4L2_PIX_FMT_YUV420N, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN },
{ V4L2_PIX_FMT_NV16, HAL_PIXEL_FORMAT_YCbCr_422_SP },
{ V4L2_PIX_FMT_NV12, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP },
{ V4L2_PIX_FMT_NV12N, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN },
{ V4L2_PIX_FMT_NV12M, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M },
{ V4L2_PIX_FMT_NV12N_10B, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B },
{ V4L2_PIX_FMT_YUYV, HAL_PIXEL_FORMAT_YCbCr_422_I },
{ V4L2_PIX_FMT_UYVY, HAL_PIXEL_FORMAT_EXYNOS_CbYCrY_422_I },
{ V4L2_PIX_FMT_NV61, HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_SP },
{ V4L2_PIX_FMT_NV21M, HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M },
{ V4L2_PIX_FMT_NV21, HAL_PIXEL_FORMAT_YCrCb_420_SP },
{ V4L2_PIX_FMT_NV12MT_16X16, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_TILED },
{ V4L2_PIX_FMT_NV12NT, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_TILED },
{ V4L2_PIX_FMT_YVYU, HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I },
{ V4L2_PIX_FMT_VYUY, HAL_PIXEL_FORMAT_EXYNOS_CrYCbY_422_I },
{ V4L2_PIX_FMT_NV12M_P010, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M },
{ V4L2_PIX_FMT_NV12_P010, HAL_PIXEL_FORMAT_YCBCR_P010 },
{ V4L2_PIX_FMT_YUV422P, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_422_P },
{ V4L2_PIX_FMT_NV12M_SBWC_8B, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC },
{ V4L2_PIX_FMT_NV12N_SBWC_8B, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC },
{ V4L2_PIX_FMT_NV12M_SBWC_10B, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC },
{ V4L2_PIX_FMT_NV12N_SBWC_10B, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC },
{ V4L2_PIX_FMT_NV21M_SBWC_8B, HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_SBWC },
{ V4L2_PIX_FMT_NV21M_SBWC_10B, HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC },
{ V4L2_PIX_FMT_NV12M_SBWCL_8B_L50, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50 },
{ V4L2_PIX_FMT_NV12M_SBWCL_8B_L75, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75 },
{ V4L2_PIX_FMT_NV12M_SBWCL_10B_L40, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L40 },
{ V4L2_PIX_FMT_NV12M_SBWCL_10B_L60, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L60 },
{ V4L2_PIX_FMT_NV12M_SBWCL_10B_L80, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L80 },
{ V4L2_PIX_FMT_NV12M_SBWCL_32_8B, HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_32_SBWC_L },
{ V4L2_PIX_FMT_NV12M_SBWCL_64_8B, HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_64_SBWC_L },
{ V4L2_PIX_FMT_NV12N_SBWCL_32_8B, HAL_PIXEL_FORMAT_EXYNOS_420_SPN_32_SBWC_L },
{ V4L2_PIX_FMT_NV12N_SBWCL_64_8B, HAL_PIXEL_FORMAT_EXYNOS_420_SPN_64_SBWC_L },
{ V4L2_PIX_FMT_NV12M_SBWCL_32_10B, HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_10B_32_SBWC_L },
{ V4L2_PIX_FMT_NV12M_SBWCL_64_10B, HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_10B_64_SBWC_L },
{ V4L2_PIX_FMT_NV12N_SBWCL_32_10B, HAL_PIXEL_FORMAT_EXYNOS_420_SPN_10B_32_SBWC_L },
{ V4L2_PIX_FMT_NV12N_SBWCL_64_10B, HAL_PIXEL_FORMAT_EXYNOS_420_SPN_10B_64_SBWC_L },
{ V4L2_PIX_FMT_NV12N_SBWC_256_8B, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_256_SBWC },
{ V4L2_PIX_FMT_NV12N_SBWC_256_10B, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_256_SBWC },
};
const int hal_to_v4l2_format_table[][2] = {
{ HAL_PIXEL_FORMAT_RGBA_8888, V4L2_PIX_FMT_RGB32 },
{ HAL_PIXEL_FORMAT_RGBX_8888, V4L2_PIX_FMT_RGB32 },
{ HAL_PIXEL_FORMAT_RGB_888, V4L2_PIX_FMT_RGB24 },
{ HAL_PIXEL_FORMAT_RGB_565, V4L2_PIX_FMT_RGB565 },
{ HAL_PIXEL_FORMAT_BGRA_8888, V4L2_PIX_FMT_BGR32 },
{ HAL_PIXEL_FORMAT_RGBA_1010102, V4L2_PIX_FMT_ABGR2101010 },
{ HAL_PIXEL_FORMAT_EXYNOS_YV12_M, V4L2_PIX_FMT_YVU420M },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M, V4L2_PIX_FMT_YUV420M },
{ HAL_PIXEL_FORMAT_YV12, V4L2_PIX_FMT_YVU420 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P, V4L2_PIX_FMT_YUV420 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN, V4L2_PIX_FMT_YUV420N },
{ HAL_PIXEL_FORMAT_YCbCr_422_SP, V4L2_PIX_FMT_NV16 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP, V4L2_PIX_FMT_NV12 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN, V4L2_PIX_FMT_NV12N },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M, V4L2_PIX_FMT_NV12M },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV, V4L2_PIX_FMT_NV12M },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B, V4L2_PIX_FMT_NV12M },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B, V4L2_PIX_FMT_NV12N_10B },
{ HAL_PIXEL_FORMAT_YCbCr_422_I, V4L2_PIX_FMT_YUYV },
{ HAL_PIXEL_FORMAT_EXYNOS_CbYCrY_422_I, V4L2_PIX_FMT_UYVY },
{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_SP, V4L2_PIX_FMT_NV61 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M, V4L2_PIX_FMT_NV21M },
{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL, V4L2_PIX_FMT_NV21M },
{ HAL_PIXEL_FORMAT_YCrCb_420_SP, V4L2_PIX_FMT_NV21 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_TILED, V4L2_PIX_FMT_NV12MT_16X16 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_TILED, V4L2_PIX_FMT_NV12NT },
{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I, V4L2_PIX_FMT_YVYU },
{ HAL_PIXEL_FORMAT_EXYNOS_CrYCbY_422_I, V4L2_PIX_FMT_VYUY },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M, V4L2_PIX_FMT_NV12M_P010 },
{ HAL_PIXEL_FORMAT_YCBCR_P010, V4L2_PIX_FMT_NV12_P010 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_422_P, V4L2_PIX_FMT_YUV422P },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC, V4L2_PIX_FMT_NV12M_SBWC_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC, V4L2_PIX_FMT_NV12N_SBWC_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC, V4L2_PIX_FMT_NV12M_SBWC_10B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC, V4L2_PIX_FMT_NV12N_SBWC_10B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_SBWC, V4L2_PIX_FMT_NV21M_SBWC_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC, V4L2_PIX_FMT_NV21M_SBWC_10B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50, V4L2_PIX_FMT_NV12M_SBWCL_8B_L50 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75, V4L2_PIX_FMT_NV12M_SBWCL_8B_L75 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L40, V4L2_PIX_FMT_NV12M_SBWCL_10B_L40 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L60, V4L2_PIX_FMT_NV12M_SBWCL_10B_L60 },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L80, V4L2_PIX_FMT_NV12M_SBWCL_10B_L80 },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_32_SBWC_L, V4L2_PIX_FMT_NV12M_SBWCL_32_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_64_SBWC_L, V4L2_PIX_FMT_NV12M_SBWCL_64_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SPN_32_SBWC_L, V4L2_PIX_FMT_NV12N_SBWCL_32_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SPN_64_SBWC_L, V4L2_PIX_FMT_NV12N_SBWCL_64_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_10B_32_SBWC_L, V4L2_PIX_FMT_NV12M_SBWCL_32_10B },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SP_M_10B_64_SBWC_L, V4L2_PIX_FMT_NV12M_SBWCL_64_10B },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SPN_10B_32_SBWC_L, V4L2_PIX_FMT_NV12N_SBWCL_32_10B },
{ HAL_PIXEL_FORMAT_EXYNOS_420_SPN_10B_64_SBWC_L, V4L2_PIX_FMT_NV12N_SBWCL_64_10B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_256_SBWC, V4L2_PIX_FMT_NV12N_SBWC_256_8B },
{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_256_SBWC, V4L2_PIX_FMT_NV12N_SBWC_256_10B },
};
const uint32_t v4l2_to_hal_dataspace_table[][2] = {
{ V4L2_COLORSPACE_SRGB, HAL_DATASPACE_STANDARD_BT709 | HAL_DATASPACE_RANGE_FULL },
{ V4L2_COLORSPACE_REC709, HAL_DATASPACE_STANDARD_BT709 | HAL_DATASPACE_RANGE_LIMITED },
{ V4L2_COLORSPACE_JPEG, HAL_DATASPACE_STANDARD_BT601_625 | HAL_DATASPACE_RANGE_FULL },
{ V4L2_COLORSPACE_JPEG, HAL_DATASPACE_STANDARD_BT601_525 | HAL_DATASPACE_RANGE_FULL },
{ V4L2_COLORSPACE_SMPTE170M, HAL_DATASPACE_STANDARD_BT601_625 | HAL_DATASPACE_RANGE_LIMITED },
{ V4L2_COLORSPACE_SMPTE170M, HAL_DATASPACE_STANDARD_BT601_525 | HAL_DATASPACE_RANGE_LIMITED },
{ V4L2_COLORSPACE_BT2020, HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_RANGE_LIMITED },
{ V4L2_COLORSPACE_SRGB, HAL_DATASPACE_STANDARD_FILM | HAL_DATASPACE_RANGE_FULL },
{ V4L2_COLORSPACE_REC709, HAL_DATASPACE_STANDARD_FILM | HAL_DATASPACE_RANGE_LIMITED },
{ V4L2_COLORSPACE_SRGB, HAL_DATASPACE_SRGB },
{ V4L2_COLORSPACE_JPEG, HAL_DATASPACE_JFIF },
{ V4L2_COLORSPACE_SMPTE170M, HAL_DATASPACE_BT601_525 },
{ V4L2_COLORSPACE_SMPTE170M, HAL_DATASPACE_BT601_625 },
{ V4L2_COLORSPACE_REC709, HAL_DATASPACE_BT709 },
};
int v4l2_pixfmt_to_hal(int v4l2_pixel_format)
{
for (uint32_t i = 0; i < ARRSIZE(v4l2_to_hal_format_table); i++) {
if (v4l2_to_hal_format_table[i][0] == v4l2_pixel_format)
return v4l2_to_hal_format_table[i][1];
}
ALOGE("Unsupported v4l2 pixel format(%#x)", v4l2_pixel_format);
return 0;
}
int hal_pixfmt_to_v4l2(int hal_pixel_format)
{
for (uint32_t i = 0; i < ARRSIZE(hal_to_v4l2_format_table); i++) {
if (hal_to_v4l2_format_table[i][0] == hal_pixel_format)
return hal_to_v4l2_format_table[i][1];
}
ALOGE("Unsupported hal pixel format(%#x)", hal_pixel_format);
return 0;
}
int v4l2_dataspace_to_hal(unsigned int v4l2_dataspace, unsigned int *hal_colorspace)
{
for (uint32_t i = 0; i < ARRSIZE(v4l2_to_hal_dataspace_table); i++) {
if (v4l2_to_hal_dataspace_table[i][0] == v4l2_dataspace) {
*hal_colorspace = v4l2_to_hal_dataspace_table[i][1];
return 0;
}
}
ALOGE("Unsupported v4l2 dataspace(%#x)", v4l2_dataspace);
return -1;
}
void *exynos_sc_create(int dev_num)
{
CScalerAcryl *sc = new CScalerAcryl();
if (!sc) {
ALOGE("Failed to allocate a Scaler handle for instance %d", dev_num);
return nullptr;
}
if (!sc->Valid()) {
ALOGE("Failed to create a Scaler handle for instance %d", dev_num);
delete sc;
return nullptr;
}
return reinterpret_cast<void *>(sc);
}
int exynos_sc_destroy(void *handle)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
delete sc;
return 0;
}
int exynos_sc_set_csc_property(
void *handle,
unsigned int __unused csc_range,
unsigned int v4l2_colorspace,
unsigned int filter)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
unsigned int hal_colorspace;
if (v4l2_dataspace_to_hal(v4l2_colorspace, &hal_colorspace) < 0)
return -1;
sc->SetCSCEq(hal_colorspace);
sc->SetFilter(filter);
return 0;
}
int exynos_sc_set_src_format(
void *handle,
unsigned int width,
unsigned int height,
unsigned int crop_left,
unsigned int crop_top,
unsigned int crop_width,
unsigned int crop_height,
unsigned int v4l2_colorformat,
unsigned int __unused cacheable,
unsigned int mode_drm,
unsigned int __unused premultiplied)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
sc->SetDRM(mode_drm != 0);
sc->SetSrcCrop(crop_left, crop_top, crop_width, crop_height);
sc->SetSrcInfo(width, height, v4l2_colorformat);
AcrylicLayer *layer = sc->getLayer();
if (!layer->setImageDimension(width, height))
return -1;
if (!layer->setImageType(v4l2_pixfmt_to_hal(v4l2_colorformat), sc->GetCSCEq()))
return -1;
return 0;
}
int exynos_sc_set_dst_format(
void *handle,
unsigned int width,
unsigned int height,
unsigned int crop_left,
unsigned int crop_top,
unsigned int crop_width,
unsigned int crop_height,
unsigned int v4l2_colorformat,
unsigned int __unused cacheable,
unsigned int mode_drm,
unsigned int __unused premultiplied)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
sc->SetDRM(mode_drm != 0);
sc->SetDstCrop(crop_left, crop_top, crop_width, crop_height);
sc->SetDstInfo(width, height, v4l2_colorformat);
Acrylic *acrylHandle = sc->getHandle();
if (!acrylHandle->setCanvasDimension(width, height))
return -1;
if (!acrylHandle->setCanvasImageType(v4l2_pixfmt_to_hal(v4l2_colorformat), sc->GetCSCEq()))
return -1;
return 0;
}
int exynos_sc_set_rotation(
void *handle,
int rot,
int flip_h,
int flip_v)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
return sc->SetRotate(rot, flip_h, flip_v) ? 0 : -1;
}
void exynos_sc_set_framerate(
void *handle,
int framerate)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return;
sc->SetFrameRate(framerate);
}
int exynos_sc_set_src_addr(
void *handle,
void *addr[SC_NUM_OF_PLANES],
int mem_type,
int __unused acquireFenceFd)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
AcrylicLayer *layer = sc->getLayer();
int buf_count = sc->GetSrcPlaneCount();
if (mem_type == V4L2_MEMORY_DMABUF) {
int fd[SC_NUM_OF_PLANES];
size_t len[SC_NUM_OF_PLANES];
off_t offset[SC_NUM_OF_PLANES];
for (int i = 0; i < buf_count; i++) {
fd[i] = reinterpret_cast<intptr_t>(addr[i]);
len[i] = sc->GetSrcPlaneSize(i);
offset[i] = 0;
}
if (!layer->setImageBuffer(fd, len, offset, buf_count, -1, 0))
return -1;
} else if (mem_type == V4L2_MEMORY_USERPTR) {
size_t len[SC_NUM_OF_PLANES];
for (int i = 0; i < buf_count; i++)
len[i] = sc->GetSrcPlaneSize(i);
if (!layer->setImageBuffer(addr, len, buf_count, 0))
return -1;
} else
return -1;
return 0;
}
int exynos_sc_set_dst_addr(
void *handle,
void *addr[SC_NUM_OF_PLANES],
int mem_type,
int __unused acquireFenceFd)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
Acrylic *acrylHandle = sc->getHandle();
int buf_count = sc->GetDstPlaneCount();
uint32_t attr = sc->GetDRM() ? AcrylicCanvas::ATTR_PROTECTED : AcrylicCanvas::ATTR_NONE;
if (mem_type == V4L2_MEMORY_DMABUF)
{
int fd[SC_NUM_OF_PLANES];
size_t len[SC_NUM_OF_PLANES];
off_t offset[SC_NUM_OF_PLANES];
for (int i = 0; i < buf_count; i++) {
fd[i] = reinterpret_cast<intptr_t>(addr[i]);
len[i] = sc->GetDstPlaneSize(i);
offset[i] = 0;
}
if (!acrylHandle->setCanvasBuffer(fd, len, offset, buf_count, -1, attr))
return -1;
} else if (mem_type == V4L2_MEMORY_USERPTR) {
size_t len[SC_NUM_OF_PLANES];
for (int i = 0; i < buf_count; i++)
len[i] = sc->GetDstPlaneSize(i);
if (!acrylHandle->setCanvasBuffer(addr, len, buf_count, attr))
return -1;
} else
return -1;
return 0;
}
int exynos_sc_convert(void *handle)
{
CScalerAcryl *sc = reinterpret_cast<CScalerAcryl *>(handle);
if (!sc)
return -1;
AcrylicLayer *layer = sc->getLayer();
layer->setCompositMode(HWC_BLENDING_NONE, 255, 0);
layer->setCompositArea(sc->GetSrcCrop(), sc->GetDstCrop(), sc->GetTransform(), 0);
Acrylic *acrylHandle = sc->getHandle();
if (!acrylHandle->execute(nullptr))
return -1;
return 0;
}
/* CScalerAcryl */
struct PixFormat {
unsigned int pixfmt;
char planes;
unsigned short bit_pp[3];
};
const static PixFormat g_pixfmt_table[] = {
{V4L2_PIX_FMT_RGB32, 1, {32, 0, 0}, },
{V4L2_PIX_FMT_BGR32, 1, {32, 0, 0}, },
{V4L2_PIX_FMT_RGB565, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_RGB555X, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_RGB444, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_ABGR2101010, 1, {32, 0, 0}, },
{V4L2_PIX_FMT_YUYV, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_YVYU, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_UYVY, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_NV16, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_NV61, 1, {16, 0, 0}, },
{V4L2_PIX_FMT_YUV420, 1, {12, 0, 0}, },
{V4L2_PIX_FMT_YVU420, 1, {12, 0, 0}, },
{V4L2_PIX_FMT_NV12M, 2, {8, 4, 0}, },
{V4L2_PIX_FMT_NV21M, 2, {8, 4, 0}, },
{v4l2_fourcc('V', 'M', '1', '2'), 2, {8, 4, 0}, },
{V4L2_PIX_FMT_NV12, 1, {12, 0, 0}, },
{V4L2_PIX_FMT_NV21, 1, {12, 0, 0}, },
{v4l2_fourcc('N', 'M', '2', '1'), 2, {8, 4, 0}, },
{V4L2_PIX_FMT_YUV420M, 3, {8, 2, 2}, },
{V4L2_PIX_FMT_YVU420M, 3, {8, 2, 2}, },
{V4L2_PIX_FMT_NV12M_P010, 2, {16, 8, 0}, },
{V4L2_PIX_FMT_NV12_P010, 1, {24, 0, 0}, },
{V4L2_PIX_FMT_NV24, 1, {24, 0, 0}, },
{V4L2_PIX_FMT_NV42, 1, {24, 0, 0}, },
{V4L2_PIX_FMT_YUV422P, 1, {16, 0, 0}, },
/*
* In SBWC foramt, bit_pp is meaningless to calculate size.
* So, in this, meaning of bit_pp is different.
* 1. bit_pp[0] : if 0, this format is SBWC format.
* if 27, this format is SBWC format of version 2.7.
* 2. bit_pp[1] : this format is 8 or 10 bit format.
* 3. bit_pp[2] : it means blocksize of SBWC lossy.
* In SBWC version 2.7, this means alignment.
*/
{V4L2_PIX_FMT_NV12M_SBWC_8B, 2, {0, 8, 0}, },
{V4L2_PIX_FMT_NV21M_SBWC_8B, 2, {0, 8, 0}, },
{V4L2_PIX_FMT_NV12N_SBWC_8B, 1, {0, 8, 0}, },
{V4L2_PIX_FMT_NV12M_SBWC_10B, 2, {0, 10, 0}, },
{V4L2_PIX_FMT_NV21M_SBWC_10B, 2, {0, 10, 0}, },
{V4L2_PIX_FMT_NV12N_SBWC_10B, 1, {0, 10, 0}, },
{V4L2_PIX_FMT_NV12M_SBWCL_8B_L50, 2, {0, 8, 64}, },
{V4L2_PIX_FMT_NV12M_SBWCL_8B_L75, 2, {0, 8, 96}, },
{V4L2_PIX_FMT_NV12M_SBWCL_10B_L40, 2, {0, 10, 64}, },
{V4L2_PIX_FMT_NV12M_SBWCL_10B_L60, 2, {0, 10, 96}, },
{V4L2_PIX_FMT_NV12M_SBWCL_10B_L80, 2, {0, 10, 128}, },
{V4L2_PIX_FMT_NV12M_SBWCL_32_8B, 2, {27, 8, 32}, },
{V4L2_PIX_FMT_NV12M_SBWCL_64_8B, 2, {27, 8, 64}, },
{V4L2_PIX_FMT_NV12N_SBWCL_32_8B, 1, {27, 8, 32}, },
{V4L2_PIX_FMT_NV12N_SBWCL_64_8B, 1, {27, 8, 64}, },
{V4L2_PIX_FMT_NV12M_SBWCL_32_10B, 2, {27, 10, 32}, },
{V4L2_PIX_FMT_NV12M_SBWCL_64_10B, 2, {27, 10, 64}, },
{V4L2_PIX_FMT_NV12N_SBWCL_32_10B, 1, {27, 10, 32}, },
{V4L2_PIX_FMT_NV12N_SBWCL_64_10B, 1, {27, 10, 64}, },
{V4L2_PIX_FMT_NV12N_SBWC_256_8B, 1, {27, 8, 256}, },
{V4L2_PIX_FMT_NV12N_SBWC_256_10B, 1, {27, 10, 256}, },
};
CScalerAcryl::CScalerAcryl() : mDRM(false), mColorSpace(0), mTransform(0), mFilter(0), mFramerate(0)
{
mAcrylicHandle = Acrylic::createScaler();
if (mAcrylicHandle == nullptr) {
ALOGE("Failed to create default scaler");
} else {
mLayer = mAcrylicHandle->createLayer();
if (mLayer == nullptr) {
ALOGE("Failed to create layer");
delete mAcrylicHandle;
mAcrylicHandle = nullptr;
}
}
memset(&mSrcInfo, 0, sizeof(frameInfo));
memset(&mDstInfo, 0, sizeof(frameInfo));
}
CScalerAcryl::~CScalerAcryl()
{
delete mLayer;
delete mAcrylicHandle;
}
/* helper macros */
#ifndef __ALIGN_UP
#define __ALIGN_UP(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#endif
/* SBWC */
/* w: width, h: height, b: block size, a: alignment, s: stride */
#define SBWC_STRIDE(w, b, a) __ALIGN_UP(((b) * (((w) + 31) / 32)), a)
#define SBWC_HEADER_STRIDE(w) ((((((w) + 63) / 64) + 15) / 16) * 16)
#define SBWC_Y_SIZE(s, h) (((s) * ((__ALIGN_UP((h), 16) + 3) / 4)) + 64)
#define SBWC_CBCR_SIZE(s, h) (((s) * (((__ALIGN_UP((h), 16) / 2) + 3) / 4)) + 64)
#define SBWC_Y_HEADER_SIZE(w, h) __ALIGN_UP(((SBWC_HEADER_STRIDE(w) * ((__ALIGN_UP((h), 16) + 3) / 4)) + 256), 32)
#define SBWC_CBCR_HEADER_SIZE(w, h) ((SBWC_HEADER_STRIDE(w) * (((__ALIGN_UP((h), 16) / 2) + 3) / 4)) + 128)
/* SBWC 32B align */
#define SBWC_8B_STRIDE(w) SBWC_STRIDE(w, 128, 1)
#define SBWC_10B_STRIDE(w) SBWC_STRIDE(w, 160, 1)
#define SBWC_8B_Y_SIZE(w, h) SBWC_Y_SIZE(SBWC_8B_STRIDE(w), h)
#define SBWC_8B_Y_HEADER_SIZE(w, h) SBWC_Y_HEADER_SIZE(w, h)
#define SBWC_8B_CBCR_SIZE(w, h) SBWC_CBCR_SIZE(SBWC_8B_STRIDE(w), h)
#define SBWC_8B_CBCR_HEADER_SIZE(w, h) SBWC_CBCR_HEADER_SIZE(w, h)
#define SBWC_10B_Y_SIZE(w, h) SBWC_Y_SIZE(SBWC_10B_STRIDE(w), h)
#define SBWC_10B_Y_HEADER_SIZE(w, h) __ALIGN_UP((((__ALIGN_UP((w), 32) * __ALIGN_UP((h), 16) * 2) + 256) - SBWC_10B_Y_SIZE(w, h)), 32)
#define SBWC_10B_CBCR_SIZE(w, h) SBWC_CBCR_SIZE(SBWC_10B_STRIDE(w), h)
#define SBWC_10B_CBCR_HEADER_SIZE(w, h) (((__ALIGN_UP((w), 32) * __ALIGN_UP((h), 16)) + 256) - SBWC_10B_CBCR_SIZE(w, h))
/* SBWC 256B align */
#define SBWC_256_8B_STRIDE(w) SBWC_STRIDE(w, 128, 256)
#define SBWC_256_10B_STRIDE(w) SBWC_STRIDE(w, 256, 1)
#define SBWC_256_8B_Y_SIZE(w, h) SBWC_Y_SIZE(SBWC_256_8B_STRIDE(w), h)
#define SBWC_256_8B_Y_HEADER_SIZE(w, h) SBWC_Y_HEADER_SIZE(w, h)
#define SBWC_256_8B_CBCR_SIZE(w, h) SBWC_CBCR_SIZE(SBWC_256_8B_STRIDE(w), h)
#define SBWC_256_8B_CBCR_HEADER_SIZE(w, h) SBWC_CBCR_HEADER_SIZE(w, h)
#define SBWC_256_10B_Y_SIZE(w, h) SBWC_Y_SIZE(SBWC_256_10B_STRIDE(w), h)
#define SBWC_256_10B_Y_HEADER_SIZE(w, h) SBWC_Y_HEADER_SIZE(w, h)
#define SBWC_256_10B_CBCR_SIZE(w, h) SBWC_CBCR_SIZE(SBWC_256_10B_STRIDE(w), h)
#define SBWC_256_10B_CBCR_HEADER_SIZE(w, h) SBWC_CBCR_HEADER_SIZE(w, h)
/* SBWC lossy buffer size */
#define SBWCL_BLOCK_COUNT(w, h) (ALIGN(w, 32) * ALIGN(h, 4) / 128)
#define SBWCL_Y_SIZE(w, h, r) (SBWCL_STRIDE(w, r) * ((ALIGN(h, 16) + 3) / 4) + 64)
#define SBWCL_CBCR_SIZE(w, h, r) (SBWCL_STRIDE(w, r) * (((ALIGN(h, 16) / 2) + 3) / 4) + 64)
#define SBWCL_STRIDE(w, r) (ALIGN(w, 32) * (r))
/* SBWC Lossy v2.7 32B/64B align */
#define SBWCL_32_STRIDE(w) (96 * (((w) + 31) / 32))
#define SBWCL_64_STRIDE(w) (128 * (((w) + 31) / 32))
#define SBWCL_HEADER_STRIDE(w) ((((((w) + 63) / 64) + 15) / 16) * 16)
#define SBWCL_32_Y_SIZE(w, h) (SBWCL_32_STRIDE(w) * (((h) + 3) / 4))
#define SBWCL_32_CBCR_SIZE(w, h) (SBWCL_32_STRIDE(w) * ((((h) / 2) + 3) / 4))
#define SBWCL_64_Y_SIZE(w, h) (SBWCL_64_STRIDE(w) * (((h) + 3) / 4))
#define SBWCL_64_CBCR_SIZE(w, h) (SBWCL_64_STRIDE(w) * ((((h) / 2) + 3) / 4))
#define SBWCL_Y_HEADER_SIZE(w, h) ((SBWCL_HEADER_STRIDE(w) * (((h) + 3) / 4)) + 64)
#define SBWCL_CBCR_HEADER_SIZE(w, h) ((SBWCL_HEADER_STRIDE(w) * ((((h) / 2) + 3) / 4)) + 64)
#define pixIsSbwc(pixFmt) ((pixFmt)->bit_pp[0] == 0)
#define pixIsSbwc27(pixFmt) ((pixFmt)->bit_pp[0] == 27)
#define pixGetBitOfSbwc(pixFmt) ((pixFmt)->bit_pp[1])
#define pixIsSbwcLossless(pixFmt) (pixIsSbwc(pixFmt) && (pixFmt)->bit_pp[2] == 0)
#define pixIsSbwcLossyWithComp(pixFmt) (pixIsSbwc(pixFmt) && (pixFmt)->bit_pp[2] != 0)
#define pixGetBlockSizeOfSbwcLossy(pixFmt) ((pixFmt)->bit_pp[2])
#define pixGetByte32NumOfSbwcLossy(pixFmt) ((pixFmt)->bit_pp[2] / 32)
#define pixGetAlignmentOfSbwc(pixFmt) ((pixFmt)->bit_pp[2])
#ifdef SCALER_ALIGN_RESTRICTION
#define SCALER_EXT_ALIGN 128
#define SCALER_EXT_SIZE 512
#endif
bool CScalerAcryl::SetFormat(frameInfo &info, unsigned int width, unsigned int height,
unsigned int v4l2_fmt, bool isSrc) {
(void)isSrc; // prevent unused warning instead of using [[maybe_unused]] of C++17
const PixFormat *pixfmt = nullptr;
for (size_t i = 0; i < ARRSIZE(g_pixfmt_table); i++) {
if (g_pixfmt_table[i].pixfmt == v4l2_fmt) {
pixfmt = &g_pixfmt_table[i];
break;
}
}
if (!pixfmt) {
ALOGE("Format %#x is not supported", v4l2_fmt);
return false;
}
if (pixIsSbwc(pixfmt) || pixIsSbwc27(pixfmt)) {
if (pixIsSbwcLossyWithComp(pixfmt)) {
info.len[0] = SBWCL_Y_SIZE(width, height, pixGetByte32NumOfSbwcLossy(pixfmt));
info.len[1] = SBWCL_CBCR_SIZE(width, height, pixGetByte32NumOfSbwcLossy(pixfmt));
} else if (pixIsSbwcLossless(pixfmt)) {
if (pixGetBitOfSbwc(pixfmt) == 8) {
info.len[0] = SBWC_8B_Y_SIZE(width, height) +
SBWC_8B_Y_HEADER_SIZE(width, height);
info.len[1] = SBWC_8B_CBCR_SIZE(width, height) +
SBWC_8B_CBCR_HEADER_SIZE(width, height);
} else {
info.len[0] = SBWC_10B_Y_SIZE(width, height) +
SBWC_10B_Y_HEADER_SIZE(width, height);
info.len[1] = SBWC_10B_CBCR_SIZE(width, height) +
SBWC_10B_CBCR_HEADER_SIZE(width, height);
}
} else {
if (pixGetAlignmentOfSbwc(pixfmt) == 32) {
info.len[0] = SBWCL_32_Y_SIZE(width, height) +
SBWCL_Y_HEADER_SIZE(width, height);
info.len[1] = SBWCL_32_CBCR_SIZE(width, height) +
SBWCL_CBCR_HEADER_SIZE(width, height);
} else if (pixGetAlignmentOfSbwc(pixfmt) == 64) {
info.len[0] = SBWCL_64_Y_SIZE(width, height) +
SBWCL_Y_HEADER_SIZE(width, height);
info.len[1] = SBWCL_64_CBCR_SIZE(width, height) +
SBWCL_CBCR_HEADER_SIZE(width, height);
} else if (pixGetAlignmentOfSbwc(pixfmt) == 256) {
if (pixGetBitOfSbwc(pixfmt) == 8) {
info.len[0] = SBWC_256_8B_Y_SIZE(width, height) +
SBWC_256_8B_Y_HEADER_SIZE(width, height);
info.len[1] = SBWC_256_8B_CBCR_SIZE(width, height) +
SBWC_256_8B_CBCR_HEADER_SIZE(width, height);
} else {
info.len[0] = SBWC_256_10B_Y_SIZE(width, height) +
SBWC_256_10B_Y_HEADER_SIZE(width, height);
info.len[1] = SBWC_256_10B_CBCR_SIZE(width, height) +
SBWC_256_10B_CBCR_HEADER_SIZE(width, height);
}
}
}
if (pixfmt->planes == 1) {
info.len[0] += info.len[1];
info.len[1] = 0;
}
} else {
for (int i = 0; i < pixfmt->planes; i++) {
if (((pixfmt->bit_pp[i] * width) % 8) != 0) {
ALOGE("Plane %d of format %#x must have even width", i, v4l2_fmt);
return false;
}
info.len[i] = (pixfmt->bit_pp[i] * width * height) / 8;
}
if (pixfmt->pixfmt == V4L2_PIX_FMT_YVU420) {
unsigned int y_size = width * height;
unsigned int c_span = ALIGN(width / 2, 16);
info.len[0] = y_size + (c_span * height / 2) * 2;
}
#ifdef SCALER_ALIGN_RESTRICTION
if (isSrc && (width % SCALER_EXT_ALIGN)) {
for (int i = 0; i < pixfmt->planes; i++)
info.len[i] += (i == 0) ? SCALER_EXT_SIZE : SCALER_EXT_SIZE / 2;
}
#endif
}
info.num_buffers = pixfmt->planes;
return true;
}
bool CScalerAcryl::SetRotate(int rot, int hflip, int vflip)
{
if ((rot % 90) != 0) {
ALOGE("Rotation degree %d must be multiple of 90", rot);
return false;
}
switch (rot) {
case 90:
mTransform |= HAL_TRANSFORM_ROT_90;
break;
case 180:
mTransform |= HAL_TRANSFORM_ROT_180;
break;
case 270:
mTransform |= HAL_TRANSFORM_ROT_270;
break;
default:
mTransform = 0;
break;
}
if (hflip)
mTransform |= HAL_TRANSFORM_FLIP_H;
if (vflip)
mTransform |= HAL_TRANSFORM_FLIP_V;
return true;
}
/* Dummies to avoid build error */
void *exynos_sc_create_exclusive(
int __unused dev_num,
int __unused allow_drm)
{
return nullptr;
}
int exynos_sc_csc_exclusive(void __unused *handle,
unsigned int __unused range_full,
unsigned int __unused v4l2_colorspace)
{
return 0;
}
int exynos_sc_config_exclusive(
void __unused *handle,
exynos_sc_img __unused *src_img,
exynos_sc_img __unused *dst_img)
{
return 0;
}
int exynos_sc_run_exclusive(
void __unused *handle,
exynos_sc_img __unused *src_img,
exynos_sc_img __unused *dst_img)
{
return 0;
}
void *exynos_sc_create_blend_exclusive(
int __unused dev_num,
int __unused allow_drm)
{
return 0;
}
int exynos_sc_config_blend_exclusive(
void __unused *handle,
exynos_sc_img __unused *src_img,
exynos_sc_img __unused *dst_img,
struct SrcBlendInfo __unused *srcblendinfo)
{
return 0;
}
int exynos_sc_wait_frame_done_exclusive(void __unused *handle) {return 0; }
int exynos_sc_stop_exclusive(void __unused *handle) { return 0; }
int exynos_sc_free_and_close(void __unused *handle) { return 0; }