/* * Copyright (C) 2021 Rockchip Electronics Co., Ltd. * Authors: * Cerf Yu * * 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 "im2d.h" #include "im2d_common.h" #include "im2d_hardware.h" #include "RockchipRga.h" #include "core/NormalRga.h" #include "RgaUtils.h" #ifdef ANDROID using namespace android; #endif #define MAX(n1, n2) ((n1) > (n2) ? (n1) : (n2)) #define GET_GCD(n1, n2) \ ({ \ int i; \ for(i = 1; i <= (n1) && i <= (n2); i++) { \ if((n1) % i==0 && (n2) % i==0) \ gcd = i; \ } \ gcd; \ }) #define GET_LCM(n1, n2, gcd) (((n1) * (n2)) / gcd) extern struct rgaContext *rgaCtx; extern __thread char rga_err_str[ERR_MSG_LEN]; IM_API static IM_STATUS rga_get_context(void) { if (rgaCtx == NULL) { RockchipRga& rkRga(RockchipRga::get()); if (rgaCtx == NULL) { ALOGE("rga_im2d: The current RockchipRga singleton is destroyed. " "Please check if RkRgaInit/RkRgaDeInit are called, if so, please disable them."); imSetErrorMsg("The current RockchipRga singleton is destroyed." "Please check if RkRgaInit/RkRgaDeInit are called, if so, please disable them."); return IM_STATUS_FAILED; } } return IM_STATUS_SUCCESS; } static IM_STATUS rga_support_info_merge_table(rga_info_table_entry *dst_table, rga_info_table_entry *merge_table) { if (dst_table == NULL || merge_table == NULL) { ALOGE("%s[%d] dst or merge table is NULL!\n", __FUNCTION__, __LINE__); return IM_STATUS_FAILED; } dst_table->version |= merge_table->version; dst_table->input_format |= merge_table->input_format; dst_table->output_format |= merge_table->output_format; dst_table->feature |= merge_table->feature; dst_table->input_resolution = MAX(dst_table->input_resolution, merge_table->input_resolution); dst_table->output_resolution = MAX(dst_table->output_resolution, merge_table->output_resolution); dst_table->byte_stride = MAX(dst_table->byte_stride, merge_table->byte_stride); dst_table->scale_limit = MAX(dst_table->scale_limit, merge_table->scale_limit); dst_table->performance = MAX(dst_table->performance, merge_table->performance); return IM_STATUS_SUCCESS; } /* * rga_version_compare() - Used to compare two struct rga_version_t. * @version1 * @version2 * * if version1 > version2, return >0; * if version1 = version2, return 0; * if version1 < version2, retunr <0. */ static inline int rga_version_compare(struct rga_version_t version1, struct rga_version_t version2) { if (version1.major > version2.major) return 1; else if (version1.major == version2.major && version1.minor > version2.minor) return 1; else if (version1.major == version2.major && version1.minor == version2.minor && version1.revision > version2.revision) return 1; else if (version1.major == version2.major && version1.minor == version2.minor && version1.revision == version2.revision) return 0; return -1; } static IM_STATUS rga_yuv_legality_check(const char *name, rga_buffer_t info, im_rect rect) { if ((info.wstride % 2) || (info.hstride % 2) || (info.width % 2) || (info.height % 2) || (rect.x % 2) || (rect.y % 2) || (rect.width % 2) || (rect.height % 2)) { imSetErrorMsg("%s, Error yuv not align to 2, rect[x,y,w,h] = [%d, %d, %d, %d], " "wstride = %d, hstride = %d, format = 0x%x(%s)", name, rect.x, rect.y, info.width, info.height, info.wstride, info.hstride, info.format, translate_format_str(info.format)); return IM_STATUS_INVALID_PARAM; } return IM_STATUS_SUCCESS; } int imSetErrorMsg(const char* format, ...) { int ret = 0; va_list ap; va_start(ap, format); ret = vsnprintf(rga_err_str, ERR_MSG_LEN, format, ap); va_end(ap); return ret; } bool rga_is_buffer_valid(rga_buffer_t buf) { return (buf.phy_addr != NULL || buf.vir_addr != NULL || buf.fd > 0 || buf.handle > 0); } bool rga_is_rect_valid(im_rect rect) { return (rect.x > 0 || rect.y > 0 || (rect.width > 0 && rect.height > 0)); } void empty_structure(rga_buffer_t *src, rga_buffer_t *dst, rga_buffer_t *pat, im_rect *srect, im_rect *drect, im_rect *prect, im_opt_t *opt) { if (src != NULL) memset(src, 0, sizeof(*src)); if (dst != NULL) memset(dst, 0, sizeof(*dst)); if (pat != NULL) memset(pat, 0, sizeof(*pat)); if (srect != NULL) memset(srect, 0, sizeof(*srect)); if (drect != NULL) memset(drect, 0, sizeof(*drect)); if (prect != NULL) memset(prect, 0, sizeof(*prect)); if (opt != NULL) memset(opt, 0, sizeof(*opt)); } IM_STATUS rga_set_buffer_info(rga_buffer_t dst, rga_info_t* dstinfo) { if(NULL == dstinfo) { ALOGE("rga_im2d: invaild dstinfo"); imSetErrorMsg("Dst structure address is NULL."); return IM_STATUS_INVALID_PARAM; } if (dst.handle > 0) { dstinfo->handle = dst.handle; } else if(dst.phy_addr != NULL) { dstinfo->phyAddr= dst.phy_addr; } else if(dst.fd > 0) { dstinfo->fd = dst.fd; dstinfo->mmuFlag = 1; } else if(dst.vir_addr != NULL) { dstinfo->virAddr = dst.vir_addr; dstinfo->mmuFlag = 1; } else { ALOGE("rga_im2d: invaild dst buffer"); imSetErrorMsg("No address available in dst buffer, phy_addr = %ld, fd = %d, vir_addr = %ld, handle = %d", (unsigned long)dst.phy_addr, dst.fd, (unsigned long)dst.vir_addr, dst.handle); return IM_STATUS_INVALID_PARAM; } return IM_STATUS_SUCCESS; } IM_STATUS rga_set_buffer_info(const rga_buffer_t src, rga_buffer_t dst, rga_info_t* srcinfo, rga_info_t* dstinfo) { if(NULL == srcinfo) { ALOGE("rga_im2d: invaild srcinfo"); imSetErrorMsg("Src structure address is NULL."); return IM_STATUS_INVALID_PARAM; } if(NULL == dstinfo) { ALOGE("rga_im2d: invaild dstinfo"); imSetErrorMsg("Dst structure address is NULL."); return IM_STATUS_INVALID_PARAM; } if (src.handle > 0) { srcinfo->handle = src.handle; } else if(src.phy_addr != NULL) { srcinfo->phyAddr = src.phy_addr; } else if(src.fd > 0) { srcinfo->fd = src.fd; srcinfo->mmuFlag = 1; } else if(src.vir_addr != NULL) { srcinfo->virAddr = src.vir_addr; srcinfo->mmuFlag = 1; } else { ALOGE("rga_im2d: invaild src buffer"); imSetErrorMsg("No address available in src buffer, phy_addr = %ld, fd = %d, vir_addr = %ld, handle = %d", (unsigned long)src.phy_addr, src.fd, (unsigned long)src.vir_addr, src.handle); return IM_STATUS_INVALID_PARAM; } if (dst.handle > 0) { dstinfo->handle = dst.handle; } else if(dst.phy_addr != NULL) { dstinfo->phyAddr= dst.phy_addr; } else if(dst.fd > 0) { dstinfo->fd = dst.fd; dstinfo->mmuFlag = 1; } else if(dst.vir_addr != NULL) { dstinfo->virAddr = dst.vir_addr; dstinfo->mmuFlag = 1; } else { ALOGE("rga_im2d: invaild dst buffer"); imSetErrorMsg("No address available in dst buffer, phy_addr = %ld, fd = %d, vir_addr = %ld, handle = %d", (unsigned long)dst.phy_addr, dst.fd, (unsigned long)dst.vir_addr, dst.handle); return IM_STATUS_INVALID_PARAM; } return IM_STATUS_SUCCESS; } IM_STATUS rga_get_info(rga_info_table_entry *return_table) { int ret; int rga_version = 0; rga_info_table_entry merge_table; ret = rga_get_context(); if (ret != IM_STATUS_SUCCESS) return (IM_STATUS)ret; memset(&merge_table, 0x0, sizeof(merge_table)); for (int i = 0; i < rgaCtx->mHwVersions.size; i++) { if (rgaCtx->mHwVersions.version[i].major == 2 && rgaCtx->mHwVersions.version[i].minor == 0) { if (rgaCtx->mHwVersions.version[i].revision == 0) { rga_version = IM_RGA_HW_VERSION_RGA_2_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); } else { goto TRY_TO_COMPATIBLE; } } else if (rgaCtx->mHwVersions.version[i].major == 3 && rgaCtx->mHwVersions.version[i].minor == 0) { switch (rgaCtx->mHwVersions.version[i].revision) { case 0x16445 : rga_version = IM_RGA_HW_VERSION_RGA_2_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); break; case 0x22245 : rga_version = IM_RGA_HW_VERSION_RGA_2_ENHANCE_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); break; case 0x76831 : rga_version = IM_RGA_HW_VERSION_RGA_3_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); break; default : goto TRY_TO_COMPATIBLE; } } else if (rgaCtx->mHwVersions.version[i].major == 3 && rgaCtx->mHwVersions.version[i].minor == 2) { switch (rgaCtx->mHwVersions.version[i].revision) { case 0x18218 : rga_version = IM_RGA_HW_VERSION_RGA_2_ENHANCE_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); merge_table.feature |= IM_RGA_SUPPORT_FEATURE_ROP; break; case 0x56726 : case 0x63318 : rga_version = IM_RGA_HW_VERSION_RGA_2_ENHANCE_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); merge_table.input_format |= IM_RGA_SUPPORT_FORMAT_YUYV_422 | IM_RGA_SUPPORT_FORMAT_YUV_400; merge_table.output_format |= IM_RGA_SUPPORT_FORMAT_YUV_400 | IM_RGA_SUPPORT_FORMAT_Y4; merge_table.feature |= IM_RGA_SUPPORT_FEATURE_QUANTIZE | IM_RGA_SUPPORT_FEATURE_SRC1_R2Y_CSC | IM_RGA_SUPPORT_FEATURE_DST_FULL_CSC; break; default : goto TRY_TO_COMPATIBLE; } } else if (rgaCtx->mHwVersions.version[i].major == 3 && rgaCtx->mHwVersions.version[i].minor == 3) { switch (rgaCtx->mHwVersions.version[i].revision) { case 0x87975: rga_version = IM_RGA_HW_VERSION_RGA_2_ENHANCE_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); merge_table.input_format |= IM_RGA_SUPPORT_FORMAT_YUYV_422 | IM_RGA_SUPPORT_FORMAT_YUV_400 | IM_RGA_SUPPORT_FORMAT_RGBA2BPP; merge_table.output_format |= IM_RGA_SUPPORT_FORMAT_YUV_400 | IM_RGA_SUPPORT_FORMAT_Y4; merge_table.feature |= IM_RGA_SUPPORT_FEATURE_QUANTIZE | IM_RGA_SUPPORT_FEATURE_SRC1_R2Y_CSC | IM_RGA_SUPPORT_FEATURE_DST_FULL_CSC | IM_RGA_SUPPORT_FEATURE_MOSAIC | IM_RGA_SUPPORT_FEATURE_OSD | IM_RGA_SUPPORT_FEATURE_PRE_INTR; break; default : goto TRY_TO_COMPATIBLE; } } else if (rgaCtx->mHwVersions.version[i].major == 4 && rgaCtx->mHwVersions.version[i].minor == 0) { switch (rgaCtx->mHwVersions.version[i].revision) { case 0x18632 : rga_version = IM_RGA_HW_VERSION_RGA_2_LITE0_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); break; case 0x23998 : case 0x28610 : rga_version = IM_RGA_HW_VERSION_RGA_2_LITE1_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); merge_table.feature |= IM_RGA_SUPPORT_FEATURE_SRC1_R2Y_CSC; break; default : goto TRY_TO_COMPATIBLE; } } else if (rgaCtx->mHwVersions.version[i].major == 42 && rgaCtx->mHwVersions.version[i].minor == 0) { if (rgaCtx->mHwVersions.version[i].revision == 0x17760) { rga_version = IM_RGA_HW_VERSION_RGA_2_LITE1_INDEX; memcpy(&merge_table, &hw_info_table[rga_version], sizeof(merge_table)); } else { goto TRY_TO_COMPATIBLE; } } else { goto TRY_TO_COMPATIBLE; } rga_support_info_merge_table(return_table, &merge_table); } return IM_STATUS_SUCCESS; TRY_TO_COMPATIBLE: if (strncmp((char *)rgaCtx->mHwVersions.version[0].str, "1.3", 3) == 0) rga_version = IM_RGA_HW_VERSION_RGA_1_INDEX; else if (strncmp((char *)rgaCtx->mHwVersions.version[0].str, "1.6", 3) == 0) rga_version = IM_RGA_HW_VERSION_RGA_1_PLUS_INDEX; /*3288 vesion is 2.00*/ else if (strncmp((char *)rgaCtx->mHwVersions.version[0].str, "2.00", 4) == 0) rga_version = IM_RGA_HW_VERSION_RGA_2_INDEX; /*3288w version is 3.00*/ else if (strncmp((char *)rgaCtx->mHwVersions.version[0].str, "3.00", 4) == 0) rga_version = IM_RGA_HW_VERSION_RGA_2_INDEX; else if (strncmp((char *)rgaCtx->mHwVersions.version[0].str, "3.02", 4) == 0) rga_version = IM_RGA_HW_VERSION_RGA_2_ENHANCE_INDEX; else if (strncmp((char *)rgaCtx->mHwVersions.version[0].str, "4.00", 4) == 0) rga_version = IM_RGA_HW_VERSION_RGA_2_LITE0_INDEX; /*The version number of lite1 cannot be obtained temporarily.*/ else if (strncmp((char *)rgaCtx->mHwVersions.version[0].str, "4.00", 4) == 0) rga_version = IM_RGA_HW_VERSION_RGA_2_LITE1_INDEX; else rga_version = IM_RGA_HW_VERSION_RGA_V_ERR_INDEX; memcpy(return_table, &hw_info_table[rga_version], sizeof(rga_info_table_entry)); if (rga_version == IM_RGA_HW_VERSION_RGA_V_ERR_INDEX) { ALOGE("rga_im2d: Can not get the correct RGA version, please check the driver, version=%s\n", rgaCtx->mHwVersions.version[0].str); imSetErrorMsg("Can not get the correct RGA version, please check the driver, version=%s", rgaCtx->mHwVersions.version[0].str); return IM_STATUS_FAILED; } return IM_STATUS_SUCCESS; } IM_STATUS rga_check_driver(void) { int table_size, bind_index, least_index; bool user_bind = false; if (rgaCtx == NULL) { ALOGE("rga context is NULL!"); imSetErrorMsg("rga context is NULL!"); return IM_STATUS_FAILED; } table_size = sizeof(driver_bind_table) / sizeof(rga_dirver_bind_table_entry); /* First, find the driver version corresponding to librga. */ for (int i = (table_size - 1); i >= 0; i--) { if (rga_version_compare((struct rga_version_t) { RGA_API_MAJOR_VERSION, RGA_API_MINOR_VERSION, RGA_API_REVISION_VERSION, RGA_API_VERSION }, driver_bind_table[i].user) >= 0) { if (i == (table_size - 1)) { user_bind = true; bind_index = i; break; } else if (rga_version_compare(driver_bind_table[i + 1].user, (struct rga_version_t) { RGA_API_MAJOR_VERSION, RGA_API_MINOR_VERSION, RGA_API_REVISION_VERSION, RGA_API_VERSION }) > 0) { user_bind = true; bind_index = i; break; } } } if (user_bind) { /* Second, check whether the current driver version matches. */ if (rga_version_compare(rgaCtx->mDriverVersion, driver_bind_table[bind_index].driver) >= 0) { if (bind_index == table_size - 1) { return IM_STATUS_SUCCESS; } else if (rga_version_compare(driver_bind_table[bind_index + 1].driver, rgaCtx->mDriverVersion) > 0) { return IM_STATUS_SUCCESS; } else { /* find needs to be update version at least. */ least_index = table_size - 1; for (int i = (table_size - 1); i >= 0; i--) { if (rga_version_compare(rgaCtx->mDriverVersion, driver_bind_table[i].driver) >= 0) { if (i == (table_size - 1)) { least_index = i; break; } else if (rga_version_compare(driver_bind_table[i + 1].driver, rgaCtx->mDriverVersion) > 0) { least_index = i; break; } } } ALOGE("The librga needs to be updated to version %s at least. " "current version: librga %s, driver %s.", driver_bind_table[least_index].user.str, RGA_API_VERSION, rgaCtx->mDriverVersion.str); imSetErrorMsg("The librga needs to be updated to version %s at least. " "current version: librga %s, driver %s.", driver_bind_table[least_index].user.str, RGA_API_VERSION, rgaCtx->mDriverVersion.str); return IM_STATUS_ERROR_VERSION; } } else { ALOGE("The driver may be compatible, " "but it is best to update the driver to version %s. " "current version: librga %s, driver %s.", driver_bind_table[bind_index].driver.str, RGA_API_VERSION, rgaCtx->mDriverVersion.str); imSetErrorMsg("The driver may be compatible, " "but it is best to update the driver to version %s. " "current version: librga %s, driver %s.", driver_bind_table[bind_index].driver.str, RGA_API_VERSION, rgaCtx->mDriverVersion.str); /* Sometimes it is possible to enter compatibility mode. */ return IM_STATUS_NOERROR; } } else { ALOGE("Failed to get the version binding table of librga, " "current version: librga: %s, driver: %s", RGA_API_VERSION, rgaCtx->mDriverVersion.str); imSetErrorMsg("Failed to get the version binding table of librga, " "current version: librga: %s, driver: %s", RGA_API_VERSION, rgaCtx->mDriverVersion.str); return IM_STATUS_ERROR_VERSION; } } IM_STATUS rga_check_info(const char *name, const rga_buffer_t info, const im_rect rect, int resolution_usage) { /**************** src/dst judgment ****************/ if (info.width <= 0 || info.height <= 0 || info.format < 0) { imSetErrorMsg("Illegal %s, the parameter cannot be negative or 0, width = %d, height = %d, format = 0x%x(%s)", name, info.width, info.height, info.format, translate_format_str(info.format)); return IM_STATUS_ILLEGAL_PARAM; } if (info.width < 2 || info.height < 2) { imSetErrorMsg("Hardware limitation %s, unsupported operation of images smaller than 2 pixels, " "width = %d, height = %d", name, info.width, info.height); return IM_STATUS_ILLEGAL_PARAM; } if (info.wstride < info.width || info.hstride < info.height) { imSetErrorMsg("Invaild %s, Virtual width or height is less than actual width and height, " "wstride = %d, width = %d, hstride = %d, height = %d", name, info.wstride, info.width, info.hstride, info.height); return IM_STATUS_INVALID_PARAM; } /**************** rect judgment ****************/ if (rect.width < 0 || rect.height < 0 || rect.x < 0 || rect.y < 0) { imSetErrorMsg("Illegal %s rect, the parameter cannot be negative, rect[x,y,w,h] = [%d, %d, %d, %d]", name, rect.x, rect.y, rect.width, rect.height); return IM_STATUS_ILLEGAL_PARAM; } if ((rect.width > 0 && rect.width < 2) || (rect.height > 0 && rect.height < 2) || (rect.x > 0 && rect.x < 2) || (rect.y > 0 && rect.y < 2)) { imSetErrorMsg("Hardware limitation %s rect, unsupported operation of images smaller than 2 pixels, " "rect[x,y,w,h] = [%d, %d, %d, %d]", name, rect.x, rect.y, rect.width, rect.height); return IM_STATUS_INVALID_PARAM; } if ((rect.width + rect.x > info.wstride) || (rect.height + rect.y > info.hstride)) { imSetErrorMsg("Invaild %s rect, the sum of width and height of rect needs to be less than wstride or hstride, " "rect[x,y,w,h] = [%d, %d, %d, %d], wstride = %d, hstride = %d", name, rect.x, rect.y, rect.width, rect.height, info.wstride, info.hstride); return IM_STATUS_INVALID_PARAM; } /**************** resolution check ****************/ if (info.width > resolution_usage || info.height > resolution_usage) { imSetErrorMsg("Unsupported %s to input resolution more than %d, width = %d, height = %d", name, resolution_usage, info.width, info.height); return IM_STATUS_NOT_SUPPORTED; } else if ((rect.width > 0 && rect.width > resolution_usage) || (rect.height > 0 && rect.height > resolution_usage)) { imSetErrorMsg("Unsupported %s rect to output resolution more than %d, rect[x,y,w,h] = [%d, %d, %d, %d]", name, resolution_usage, rect.x, rect.y, rect.width, rect.height); return IM_STATUS_NOT_SUPPORTED; } return IM_STATUS_NOERROR; } IM_STATUS rga_check_limit(rga_buffer_t src, rga_buffer_t dst, int scale_usage, int mode_usage) { int src_width = 0, src_height = 0; int dst_width = 0, dst_height = 0; src_width = src.width; src_height = src.height; if (mode_usage & IM_HAL_TRANSFORM_ROT_270 || mode_usage & IM_HAL_TRANSFORM_ROT_90) { dst_width = dst.height; dst_height = dst.width; } else { dst_width = dst.width; dst_height = dst.height; } if (((src_width >> (int)(log(scale_usage)/log(2))) > dst_width) || ((src_height >> (int)(log(scale_usage)/log(2))) > dst_height)) { imSetErrorMsg("Unsupported to scaling less than 1/%d ~ %d times, src[w,h] = [%d, %d], dst[w,h] = [%d, %d]", scale_usage, scale_usage, src.width, src.height, dst.width, dst.height); return IM_STATUS_NOT_SUPPORTED; } if (((dst_width >> (int)(log(scale_usage)/log(2))) > src_width) || ((dst_height >> (int)(log(scale_usage)/log(2))) > src_height)) { imSetErrorMsg("Unsupported to scaling more than 1/%d ~ %d times, src[w,h] = [%d, %d], dst[w,h] = [%d, %d]", scale_usage, scale_usage, src.width, src.height, dst.width, dst.height); return IM_STATUS_NOT_SUPPORTED; } return IM_STATUS_NOERROR; } IM_STATUS rga_check_format(const char *name, rga_buffer_t info, im_rect rect, int format_usage, int mode_usgae) { IM_STATUS ret; int format = -1; format = RkRgaGetRgaFormat(RkRgaCompatibleFormat(info.format)); if (-1 == format) { imSetErrorMsg("illegal %s format, please query and fix, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } if (format == RK_FORMAT_RGBA_8888 || format == RK_FORMAT_BGRA_8888 || format == RK_FORMAT_RGBX_8888 || format == RK_FORMAT_BGRX_8888 || format == RK_FORMAT_ARGB_8888 || format == RK_FORMAT_ABGR_8888 || format == RK_FORMAT_XRGB_8888 || format == RK_FORMAT_XBGR_8888 || format == RK_FORMAT_RGB_888 || format == RK_FORMAT_BGR_888 || format == RK_FORMAT_RGB_565 || format == RK_FORMAT_BGR_565) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_RGB) { imSetErrorMsg("%s unsupported RGB format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } } else if (format == RK_FORMAT_RGBA_4444 || format == RK_FORMAT_BGRA_4444 || format == RK_FORMAT_RGBA_5551 || format == RK_FORMAT_BGRA_5551 || format == RK_FORMAT_ARGB_4444 || format == RK_FORMAT_ABGR_4444 || format == RK_FORMAT_ARGB_5551 || format == RK_FORMAT_ABGR_5551) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_RGB_OTHER) { imSetErrorMsg("%s unsupported RGBA 4444/5551 format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } } else if (format == RK_FORMAT_BPP1 || format == RK_FORMAT_BPP2 || format == RK_FORMAT_BPP4 || format == RK_FORMAT_BPP8) { if ((~format_usage & IM_RGA_SUPPORT_FORMAT_BPP) && !(mode_usgae & IM_COLOR_PALETTE)) { imSetErrorMsg("%s unsupported BPP format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } } else if (format == RK_FORMAT_YCrCb_420_SP || format == RK_FORMAT_YCbCr_420_SP) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUV_420_SEMI_PLANNER_8_BIT) { imSetErrorMsg("%s unsupported YUV420 semi-planner 8bit format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_YCrCb_420_P || format == RK_FORMAT_YCbCr_420_P) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUV_420_PLANNER_8_BIT) { imSetErrorMsg("%s unsupported YUV420 planner 8bit format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_YCrCb_422_SP || format == RK_FORMAT_YCbCr_422_SP) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUV_422_SEMI_PLANNER_8_BIT) { imSetErrorMsg("%s unsupported YUV422 semi-planner 8bit format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_YCrCb_422_P || format == RK_FORMAT_YCbCr_422_P) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUV_422_PLANNER_8_BIT) { imSetErrorMsg("%s unsupported YUV422 planner 8bit format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_YCrCb_420_SP_10B || format == RK_FORMAT_YCbCr_420_SP_10B) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUV_420_SEMI_PLANNER_10_BIT) { imSetErrorMsg("%s unsupported YUV420 semi-planner 10bit format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; ALOGE("If it is an RK encoder output, it needs to be aligned with an odd multiple of 256.\n"); } else if (format == RK_FORMAT_YCrCb_422_10b_SP || format == RK_FORMAT_YCbCr_422_10b_SP) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUV_422_SEMI_PLANNER_10_BIT) { imSetErrorMsg("%s unsupported YUV422 semi-planner 10bit format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; ALOGE("If it is an RK encoder output, it needs to be aligned with an odd multiple of 256.\n"); } else if (format == RK_FORMAT_YUYV_420 || format == RK_FORMAT_YVYU_420 || format == RK_FORMAT_UYVY_420 || format == RK_FORMAT_VYUY_420) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUYV_420) { imSetErrorMsg("%s unsupported YUYV format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_YUYV_422 || format == RK_FORMAT_YVYU_422 || format == RK_FORMAT_UYVY_422 || format == RK_FORMAT_VYUY_422) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUYV_422) { imSetErrorMsg("%s unsupported YUYV format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_YCbCr_400) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_YUV_400) { imSetErrorMsg("%s unsupported YUV400 format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_Y4) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_Y4) { imSetErrorMsg("%s unsupported Y4/Y1 format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } ret = rga_yuv_legality_check(name, info, rect); if (ret != IM_STATUS_SUCCESS) return ret; } else if (format == RK_FORMAT_RGBA2BPP) { if (~format_usage & IM_RGA_SUPPORT_FORMAT_RGBA2BPP) { imSetErrorMsg("%s unsupported rgba2bpp format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } } else { imSetErrorMsg("%s unsupported this format, format = 0x%x(%s)\n%s", name, info.format, translate_format_str(info.format), querystring((strcmp("dst", name) == 0) ? RGA_OUTPUT_FORMAT : RGA_INPUT_FORMAT)); return IM_STATUS_NOT_SUPPORTED; } return IM_STATUS_NOERROR; } IM_STATUS rga_check_align(const char *name, rga_buffer_t info, int byte_stride) { int bpp = 0; int bit_stride, pixel_stride, align, gcd; pixel_stride = get_perPixel_stride_from_format(info.format); bit_stride = pixel_stride * info.wstride; if (bit_stride % (byte_stride * 8) == 0) { return IM_STATUS_NOERROR; } else { gcd = GET_GCD(pixel_stride, byte_stride * 8); align = GET_LCM(pixel_stride, byte_stride * 8, gcd) / pixel_stride; imSetErrorMsg("%s unsupport width stride %d, %s width stride should be %d aligned!", name, info.wstride, translate_format_str(info.format), align); return IM_STATUS_NOT_SUPPORTED; } return IM_STATUS_NOERROR; } IM_STATUS rga_check_blend(rga_buffer_t src, rga_buffer_t pat, rga_buffer_t dst, int pat_enable, int mode_usage) { int src_fmt, pat_fmt, dst_fmt; bool src_isRGB, pat_isRGB, dst_isRGB; src_fmt = RkRgaGetRgaFormat(RkRgaCompatibleFormat(src.format)); pat_fmt = RkRgaGetRgaFormat(RkRgaCompatibleFormat(pat.format)); dst_fmt = RkRgaGetRgaFormat(RkRgaCompatibleFormat(dst.format)); src_isRGB = NormalRgaIsRgbFormat(src_fmt); pat_isRGB = NormalRgaIsRgbFormat(pat_fmt); dst_isRGB = NormalRgaIsRgbFormat(dst_fmt); /**************** blend mode check ****************/ switch (mode_usage & IM_ALPHA_BLEND_MASK) { case IM_ALPHA_BLEND_SRC : case IM_ALPHA_BLEND_DST : break; case IM_ALPHA_BLEND_SRC_OVER : if (!NormalRgaFormatHasAlpha(src_fmt)) { imSetErrorMsg("Blend mode 'src_over' unsupported src format without alpha, " "format[src,src1,dst] = [0x%x(%s), 0x%x(%s), 0x%x(%s)]", src_fmt, translate_format_str(src_fmt), pat_fmt, translate_format_str(pat_fmt), dst_fmt, translate_format_str(dst_fmt)); return IM_STATUS_NOT_SUPPORTED; } break; case IM_ALPHA_BLEND_DST_OVER : if (pat_enable) { if (!NormalRgaFormatHasAlpha(pat_fmt)) { imSetErrorMsg("Blend mode 'dst_over' unsupported pat format without alpha, " "format[src,src1,dst] = [0x%x(%s), 0x%x(%s), 0x%x(%s)]", src_fmt, translate_format_str(src_fmt), pat_fmt, translate_format_str(pat_fmt), dst_fmt, translate_format_str(dst_fmt)); return IM_STATUS_NOT_SUPPORTED; } } else { if (!NormalRgaFormatHasAlpha(dst_fmt)) { imSetErrorMsg("Blend mode 'dst_over' unsupported dst format without alpha, " "format[src,src1,dst] = [0x%x(%s), 0x%x(%s), 0x%x(%s)]", src_fmt, translate_format_str(src_fmt), pat_fmt, translate_format_str(pat_fmt), dst_fmt, translate_format_str(dst_fmt)); return IM_STATUS_NOT_SUPPORTED; } } break; default : if (!(NormalRgaFormatHasAlpha(src_fmt) || NormalRgaFormatHasAlpha(dst_fmt))) { imSetErrorMsg("Blend mode unsupported format without alpha, " "format[src,src1,dst] = [0x%x(%s), 0x%x(%s), 0x%x(%s)]", src_fmt, translate_format_str(src_fmt), pat_fmt, translate_format_str(pat_fmt), dst_fmt, translate_format_str(dst_fmt)); return IM_STATUS_NOT_SUPPORTED; } break; } /* src1 don't support scale, and src1's size must aqual to dst.' */ if (pat_enable && (pat.width != dst.width || pat.height != dst.height)) { imSetErrorMsg("In the three-channel mode Alapha blend, the width and height of the src1 channel " "must be equal to the dst channel, src1[w,h] = [%d, %d], dst[w,h] = [%d, %d]", pat.width, pat.height, dst.width, dst.height); return IM_STATUS_NOT_SUPPORTED; } return IM_STATUS_NOERROR; } IM_STATUS rga_check_rotate(int mode_usage, rga_info_table_entry &table) { if (table.version & (IM_RGA_HW_VERSION_RGA_1 | IM_RGA_HW_VERSION_RGA_1_PLUS)) { if (mode_usage & IM_HAL_TRANSFORM_FLIP_H_V) { imSetErrorMsg("RGA1/RGA1_PLUS cannot support H_V mirror."); return IM_STATUS_NOT_SUPPORTED; } if ((mode_usage & (IM_HAL_TRANSFORM_ROT_90 + IM_HAL_TRANSFORM_ROT_180 + IM_HAL_TRANSFORM_ROT_270)) && (mode_usage & (IM_HAL_TRANSFORM_FLIP_H + IM_HAL_TRANSFORM_FLIP_V + IM_HAL_TRANSFORM_FLIP_H_V))) { imSetErrorMsg("RGA1/RGA1_PLUS cannot support rotate with mirror."); return IM_STATUS_NOT_SUPPORTED; } } return IM_STATUS_NOERROR; } IM_STATUS rga_check_feature(rga_buffer_t src, rga_buffer_t pat, rga_buffer_t dst, int pat_enable, int mode_usage, int feature_usage) { if ((mode_usage & IM_COLOR_FILL) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_COLOR_FILL)) { imSetErrorMsg("The platform does not support color fill featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((mode_usage & IM_COLOR_PALETTE) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_COLOR_PALETTE)) { imSetErrorMsg("The platform does not support color palette featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((mode_usage & IM_ROP) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_ROP)) { imSetErrorMsg("The platform does not support ROP featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((mode_usage & IM_NN_QUANTIZE) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_QUANTIZE)) { imSetErrorMsg("The platform does not support quantize featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((pat_enable ? (pat.color_space_mode & IM_RGB_TO_YUV_MASK) : 0) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_SRC1_R2Y_CSC)) { imSetErrorMsg("The platform does not support src1 channel RGB2YUV color space convert featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((src.color_space_mode & IM_FULL_CSC_MASK || dst.color_space_mode & IM_FULL_CSC_MASK || (pat_enable ? (pat.color_space_mode & IM_FULL_CSC_MASK) : 0)) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_DST_FULL_CSC)) { imSetErrorMsg("The platform does not support dst channel full color space convert(Y2Y/Y2R) featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((mode_usage & IM_MOSAIC) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_MOSAIC)) { imSetErrorMsg("The platform does not support mosaic featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((mode_usage & IM_OSD) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_OSD)) { imSetErrorMsg("The platform does not support osd featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } if ((mode_usage & IM_PRE_INTR) && (~feature_usage & IM_RGA_SUPPORT_FEATURE_PRE_INTR)) { imSetErrorMsg("The platform does not support pre_intr featrue. \n%s", querystring(RGA_FEATURE)); return IM_STATUS_NOT_SUPPORTED; } return IM_STATUS_NOERROR; } IM_API IM_STATUS rga_import_buffers(struct rga_buffer_pool *buffer_pool) { int ret = 0; ret = rga_get_context(); if (ret != IM_STATUS_SUCCESS) return (IM_STATUS)ret; if (buffer_pool == NULL) { imSetErrorMsg("buffer pool is null!"); return IM_STATUS_FAILED; } ret = ioctl(rgaCtx->rgaFd, RGA_IOC_IMPORT_BUFFER, buffer_pool); if (ret < 0) { imSetErrorMsg("RGA_IOC_IMPORT_BUFFER fail! %s", strerror(errno)); return IM_STATUS_FAILED; } return IM_STATUS_SUCCESS; } IM_API rga_buffer_handle_t rga_import_buffer(uint64_t memory, int type, uint32_t size) { struct rga_buffer_pool buffer_pool; struct rga_external_buffer buffers[1]; memset(&buffer_pool, 0x0, sizeof(buffer_pool)); memset(buffers, 0x0, sizeof(buffers)); buffers[0].type = type; buffers[0].memory = memory; buffers[0].memory_info.size = size; buffer_pool.buffers = (uint64_t)buffers; buffer_pool.size = 1; if (rga_import_buffers(&buffer_pool) != IM_STATUS_SUCCESS) return -1; return buffers[0].handle; } IM_API rga_buffer_handle_t rga_import_buffer(uint64_t memory, int type, im_handle_param_t *param) { struct rga_buffer_pool buffer_pool; struct rga_external_buffer buffers[1]; memset(&buffer_pool, 0x0, sizeof(buffer_pool)); memset(buffers, 0x0, sizeof(buffers)); buffers[0].type = type; buffers[0].memory = memory; memcpy(&buffers[0].memory_info, param, sizeof(*param)); buffers[0].memory_info.format = RkRgaGetRgaFormat(buffers[0].memory_info.format) >> 8; buffer_pool.buffers = (uint64_t)buffers; buffer_pool.size = 1; if (rga_import_buffers(&buffer_pool) != IM_STATUS_SUCCESS) return -1; return buffers[0].handle; } IM_API IM_STATUS rga_release_buffers(struct rga_buffer_pool *buffer_pool) { int ret = 0; ret = rga_get_context(); if (ret != IM_STATUS_SUCCESS) return (IM_STATUS)ret; if (buffer_pool == NULL) { imSetErrorMsg("buffer pool is null!"); return IM_STATUS_FAILED; } ret = ioctl(rgaCtx->rgaFd, RGA_IOC_RELEASE_BUFFER, buffer_pool); if (ret < 0) { imSetErrorMsg("RGA_IOC_RELEASE_BUFFER fail! %s", strerror(errno)); return IM_STATUS_FAILED; } return IM_STATUS_SUCCESS; } IM_API IM_STATUS rga_release_buffer(int handle) { struct rga_buffer_pool buffer_pool; struct rga_external_buffer buffers[1]; memset(&buffer_pool, 0x0, sizeof(buffer_pool)); memset(buffers, 0x0, sizeof(buffers)); buffers[0].handle = handle; buffer_pool.buffers = (uint64_t)buffers; buffer_pool.size = 1; return rga_release_buffers(&buffer_pool); } IM_STATUS rga_get_opt(im_opt_t *opt, void *ptr) { if (opt == NULL || ptr == NULL) return IM_STATUS_FAILED; /* * Prevent the value of 'color' from being mistakenly used as * version information. */ if (rga_version_compare(RGA_GET_API_VERSION(*(im_api_version_t *)ptr), (struct rga_version_t){ 2, 0, 0, {0}}) > 0) return IM_STATUS_FAILED; if (rga_version_compare(RGA_GET_API_VERSION(*(im_api_version_t *)ptr), (struct rga_version_t){ 1, 7, 2, {0}}) <= 0) { opt->color = ((im_opt_t *)ptr)->color; memcpy(&opt->colorkey_range, &((im_opt_t *)ptr)->colorkey_range, sizeof(im_colorkey_range)); memcpy(&opt->nn, &((im_opt_t *)ptr)->nn, sizeof(im_nn_t)); opt->rop_code = ((im_opt_t *)ptr)->rop_code; opt->priority = ((im_opt_t *)ptr)->priority; opt->core = ((im_opt_t *)ptr)->core; } else { memcpy(opt, ptr, sizeof(im_opt_t)); } return IM_STATUS_SUCCESS; } IM_API im_ctx_id_t rga_begin_job(uint32_t flags) { if (rga_get_context() != IM_STATUS_SUCCESS) return IM_STATUS_FAILED; if (ioctl(rgaCtx->rgaFd, RGA_START_CONFIG, &flags) < 0) { printf(" %s(%d) start config fail: %s",__FUNCTION__, __LINE__,strerror(errno)); ALOGE(" %s(%d) start config fail: %s",__FUNCTION__, __LINE__,strerror(errno)); return IM_STATUS_FAILED; } return (im_ctx_id_t)flags; } IM_API IM_STATUS rga_cancel(im_ctx_id_t id) { if (rga_get_context() != IM_STATUS_SUCCESS) return IM_STATUS_FAILED; if (ioctl(rgaCtx->rgaFd, RGA_CANCEL_CONFIG, &id) < 0) { printf(" %s(%d) start config fail: %s",__FUNCTION__, __LINE__,strerror(errno)); ALOGE(" %s(%d) start config fail: %s",__FUNCTION__, __LINE__,strerror(errno)); return IM_STATUS_FAILED; } return IM_STATUS_SUCCESS; }