Files
luban-lite-t3e-pro/packages/artinchip/mpp/mpp_test/ge_test/scale_test.c
2025-09-30 11:56:06 +08:00

428 lines
12 KiB
C

/*
* Copyright (c) 2022-2023, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: ZeQuan Liang <zequan.liang@artinchip.com>
*/
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <aic_core.h>
#include "./public/bmp.h"
#include "./public/ge_fb.h"
#include "./public/ge_mem.h"
#define LOGE(fmt, ...) aic_log(AIC_LOG_ERR, "E", fmt, ##__VA_ARGS__)
#define LOGW(fmt, ...) aic_log(AIC_LOG_WARN, "W", fmt, ##__VA_ARGS__)
#define LOGI(fmt, ...) aic_log(AIC_LOG_INFO, "I", fmt, ##__VA_ARGS__)
/* ge scale test */
#define SCALE_WIDTH 0
#define SCALE_HEIGHT 1
#define SCALE_W_H 2
#define ONE_PIXEL 1.0
static char g_src_input[128] = {"/sdcard/ge_test/image/scale.bmp"};
static void usage(char *app)
{
printf("Usage: %s [Options]: \n", app);
printf("\t --Framebuffer uses double buffer in this test, ensure that fb0 is properly configure\n\n");
printf("\t-i --input_src, input src\n");
printf("\t-t, --type, Select scale type (default 2)\n");
printf("\t --type, 0: wide stretch, 1: height stretch, 2: width and height stretch\n\n");
printf("\t-u, --usage\n");
printf("\tfor example:\n");
printf("\tge_scale -i scale.bmp\n");
}
static long long int str2int(char *_str)
{
if (_str == NULL) {
pr_err("The string is empty!\n");
return -1;
}
if (strncmp(_str, "0x", 2)) {
return (long long)atoi(_str);
} else {
return (long long)strtoll(_str, NULL, 16);
}
}
static int bitblt_run(struct mpp_ge *ge, struct ge_bitblt *blt)
{
int ret = -1;
ret = mpp_ge_bitblt(ge, blt);
if (ret < 0) {
LOGE("bitblt task failed\n");
return ret;
}
ret = mpp_ge_emit(ge);
if (ret < 0) {
LOGE("emit task failed\n");
return ret;
}
ret = mpp_ge_sync(ge);
if (ret < 0) {
LOGE("ge sync fail\n");
return ret;
}
return 0;
}
/* use ge fill rectangle to clear screen data */
static int clear_screen(struct mpp_ge *ge, struct ge_fb_info *fb_info)
{
int ret = -1;
unsigned int fb_phy = 0;
struct ge_fillrect fill = {0};
fill.ctrl.flags = 0;
fill.type = GE_NO_GRADIENT;
fill.start_color = 0;
fill.end_color = 0;
fb_phy = fb_get_cur_frame(fb_info);
fill.dst_buf.buf_type = MPP_PHY_ADDR;
fill.dst_buf.phy_addr[0] = fb_phy;
fill.dst_buf.stride[0] = fb_info->fb_data.stride;
fill.dst_buf.size.width = fb_info->fb_data.width;
fill.dst_buf.size.height = fb_info->fb_data.height;
fill.dst_buf.format = fb_info->fb_data.format;
fill.dst_buf.crop_en = 0;
ret = mpp_ge_fillrect(ge, &fill);
if (ret < 0) {
LOGE("ge fillrect fail\n");
return -1;
}
ret = mpp_ge_emit(ge);
if (ret < 0) {
LOGE("ge emit fail\n");
return -1;
}
ret = mpp_ge_sync(ge);
if (ret < 0) {
LOGE("ge sync fail\n");
return -1;
}
return 0;
}
static int set_display_pos(struct ge_fb_info *fb_info, int width, int height, int *pos_x, int *pos_y)
{
if (width < 4 || height < 4)
return -1;
if (width > fb_info->fb_data.width)
width = fb_info->fb_data.width;
if (height > fb_info->fb_data.height)
height = fb_info->fb_data.height;
*pos_x = (fb_info->fb_data.width / 2 - width / 2);
*pos_y = (fb_info->fb_data.height / 2 - height / 2);
return 0;
}
static void display_set(struct ge_bitblt *blt, struct ge_fb_info *fb_info, struct ge_buf *buffer,
int width, int height)
{
int ret = -1;
int x = 0;
int y = 0;
unsigned int fb_phy = 0;
memset(blt, 0, sizeof(struct ge_bitblt));
/* Src layer set */
memcpy(&blt->src_buf, &buffer->buf, sizeof(struct mpp_buf));
blt->src_buf.crop_en = 1;
blt->src_buf.crop.x = 0;
blt->src_buf.crop.y = 0;
blt->src_buf.crop.width = width;
blt->src_buf.crop.height = height;
fb_phy = fb_get_cur_frame(fb_info);
ret = set_display_pos(fb_info, width, height, &x, &y);
if (ret < 0)
LOGE("set_display_pos failed.\n");
/* Dst layer set */
blt->dst_buf.buf_type = MPP_PHY_ADDR;
blt->dst_buf.phy_addr[0] = fb_phy;
blt->dst_buf.stride[0] = fb_info->fb_data.stride;
blt->dst_buf.size.width = fb_info->fb_data.width;
blt->dst_buf.size.height = fb_info->fb_data.height;
blt->dst_buf.format = fb_info->fb_data.format;
blt->dst_buf.crop_en = 1;
blt->dst_buf.crop.x = x;
blt->dst_buf.crop.y = y;
blt->dst_buf.crop.width = width;
blt->dst_buf.crop.height = height;
}
static int display(struct mpp_ge *ge, struct ge_bitblt *blt, struct ge_fb_info *fb_info, struct ge_buf *buffer,
int width, int height)
{
int ret = 0;
display_set(blt, fb_info, buffer, width, height);
ret = bitblt_run(ge, blt);
if (ret < 0) {
LOGE("bitblt_run failed\n");
return ret;
}
return ret;
}
/* Calculate the size that should be displayed and processed */
static int resize_image(double *width, double *height, int scale_type, double num,
struct bmp_header *bmp_head, struct ge_fb_info *fb_info)
{
double aspect_ration = 0;
double new_height = 0;
double new_width = 0;
float width_scale = 0;
float height_scale = 0;
aspect_ration = (*width) / (*height);
new_height = *height;
new_width = *width;
if (scale_type == SCALE_W_H) {
if (*width > *height) {
new_width = *width + num;
new_height = new_width / aspect_ration;
} else {
new_height = *height + num;
new_width = new_height * aspect_ration;
}
} else if (scale_type == SCALE_WIDTH) {
new_width += num;
} else {
new_height += num;
}
width_scale = (int)new_width / (float)bmp_head->width;
height_scale = (int)new_height / (float)abs(bmp_head->height);
/* limit the width and height to the minimum size supported by the scale function */
if (width_scale < (float)1.0 / 16 || height_scale < (float)1.0 / 16)
return 1;
if (width_scale > (float)16 || height_scale > (float)16)
return 1;
new_width = new_width >= fb_info->fb_data.width ? fb_info->fb_data.width : new_width;
new_height = new_height >= fb_info->fb_data.height ? fb_info->fb_data.height : new_height;
new_width = new_width < 4 ? 4 : new_width;
new_height = new_height < 4 ? 4 : new_height;
*width = new_width;
*height = new_height;
if ((int)*width <= 4 || (int)*height <= 4 ||
(int)*width == fb_info->fb_data.width || (int)*height == fb_info->fb_data.height)
return 1;
return 0;
}
static void ge_scale_set(struct ge_bitblt *blt, struct ge_buf *src_buffer, struct ge_buf *dst_buffer,
int width, int height)
{
memset(blt, 0, sizeof(struct ge_bitblt));
/* src layer settings */
memcpy(&blt->src_buf, &src_buffer->buf, sizeof(struct mpp_buf));
blt->src_buf.crop_en = 0;
/* dst layer settings */
memcpy(&blt->dst_buf, &dst_buffer->buf, sizeof(struct mpp_buf));
blt->dst_buf.crop_en = 1;
blt->dst_buf.crop.x = 0;
blt->dst_buf.crop.y = 0;
blt->dst_buf.crop.height = height;
blt->dst_buf.crop.width = width;
}
static int scale_run(struct mpp_ge *ge, struct ge_bitblt *blt,
struct bmp_header *bmp_head, struct ge_fb_info *fb_info,
struct ge_buf *src_buffer, struct ge_buf *dst_buffer, int scale_type)
{
int ret = 0;
int shrink_en = 1;
double width = 0;
double height = 0;
/* Obtain the width and height of the original image */
width = bmp_head->width;
height = abs(bmp_head->height);
while(1)
{
ge_scale_set(blt, src_buffer, dst_buffer, width, height);
ret = bitblt_run(ge, blt);
if (ret < 0) {
LOGE("bitblt_run error\n");
return -1;
}
ret = display(ge, blt, fb_info, dst_buffer, width, height);
if (ret < 0) {
LOGE("display error\n");
return -1;
}
fb_start_and_wait(fb_info);
fb_swap_frame(fb_info);
/* Determine whether to perform a reduction or enlargement operation */
if (shrink_en == 1)
{
ret = resize_image(&width, &height, scale_type, ONE_PIXEL,
bmp_head, fb_info);
if (ret < 0) {
LOGE("resize_image task failed\n");
return -1;
}
if (ret == 1)
shrink_en = 0;
} else {
ret = resize_image(&width, &height, scale_type, - ONE_PIXEL,
bmp_head, fb_info);
if (ret < 0) {
LOGE("resize_image task failed\n");
return -1;
}
if (ret == 1)
return 0;
}
aicos_msleep(30);
ret = clear_screen(ge, fb_info);
if (ret < 0) {
LOGE("clear_screen error\n");
return -1;
}
}
return 0;
}
static void scale_test(int argc, char **argv)
{
int ret = -1;
int scale_type = 0;
int bmp_fd = -1;
enum mpp_pixel_format bmp_fmt = 0;
struct mpp_ge *ge = NULL;
struct ge_bitblt blt = {0};
struct ge_fb_info *fb_info = NULL;
struct ge_buf *bmp_buffer = NULL;
struct ge_buf *dst_buffer = NULL;
struct bmp_header bmp_head = {0};
const char sopts[] = "ut:i:";
const struct option lopts[] = {
{"usage", no_argument, NULL, 'u'},
{"type", required_argument, NULL, 't'},
{"src_input" , required_argument, NULL, 'i'},
{0, 0, 0, 0}
};
optind = 0;
while ((ret = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
switch (ret) {
case 'i':
strncpy(g_src_input, optarg, sizeof(g_src_input) - 1);
break;
case 't':
scale_type = str2int(optarg);
if ((scale_type > 2) || (scale_type < 0)) {
printf("scale_type invalid, please set against\n");
return;
}
break;
case 'u':
usage(argv[0]);
return;
default:
LOGE("Invalid parameter: %#x\n", ret);
return;
}
}
ge = mpp_ge_open();
if (!ge) {
LOGE("open ge device error\n");
goto EXIT;
}
fb_info = fb_open();
bmp_fd = bmp_open(g_src_input, &bmp_head);
if (bmp_fd < 0) {
LOGE("open bmp error, path = %s\n", g_src_input);
goto EXIT;
}
bmp_fmt = bmp_get_fmt(&bmp_head);
bmp_buffer = ge_buf_malloc(bmp_head.width, abs(bmp_head.height), bmp_fmt);
if (bmp_buffer == NULL) {
LOGE("malloc bmp_buffer error\n");
goto EXIT;
}
dst_buffer = ge_buf_malloc(fb_info->fb_data.width, fb_info->fb_data.height, fb_info->fb_data.format);
if (dst_buffer == NULL) {
LOGE("malloc dst_buffer error\n");
goto EXIT;
}
ret = bmp_read(bmp_fd, (void *)((uintptr_t)bmp_buffer->buf.phy_addr[0]), &bmp_head);
if (ret < 0) {
LOGE("bmp_read error\n");
goto EXIT;
}
ge_buf_clean_dcache(bmp_buffer);
/* The ge operation here does not involve the CPU and does not required cleaning the dcache */
ret = scale_run(ge, &blt, &bmp_head, fb_info,
bmp_buffer, dst_buffer, scale_type);
if (ret < 0) {
LOGE("scale_run task failed: %d\n", ret);
goto EXIT;
}
printf("ge scale test success\n");
EXIT:
if (bmp_fd > 0)
bmp_close(bmp_fd);
if (ge)
mpp_ge_close(ge);
if (fb_info)
fb_close(fb_info);
if (bmp_buffer)
ge_buf_free(bmp_buffer);
if (dst_buffer)
ge_buf_free(dst_buffer);
}
MSH_CMD_EXPORT_ALIAS(scale_test, ge_scale, ge scale test);