TRIMUI SMART >> C/C++
Screen Scaling
參考資訊:
1. MinUI
main.c
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <time.h>
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
ION_HEAP_TYPE_CARVEOUT,
ION_HEAP_TYPE_CHUNK,
ION_HEAP_TYPE_DMA,
ION_HEAP_TYPE_CUSTOM,
ION_NUM_HEAPS = 16,
};
#define FB_CH 0
#define FB_LAYER 0
#define FB_ZORDER 0
#define SCALER_CH 1
#define SCALER_LAYER 0
#define SCALER_ZORDER 10
#define OVERLAY_CH 2
#define OVERLAY_LAYER 0
#define OVERLAY_ZORDER 11
#define DEF_FB_CH 2
#define DEF_FB_LAYER 0
#define DE 0x01000000
#define RT_MIXER0 (DE + 0x00100000)
#define OVL_V (RT_MIXER0 + 0x2000 + (SCALER_CH * 0x1000))
#define OVL_V_TOP_LADD0 (0x18 + (SCALER_LAYER * 0x30))
#define ION_IOC_SUNXI_PHYS_ADDR 7
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
#define ION_IOC_MAGIC 'I'
#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
struct ion_handle_data {
struct ion_handle *handle;
};
typedef struct {
void *handle;
unsigned int phys_addr;
unsigned int size;
} sunxi_phys_data;
struct ion_allocation_data {
size_t len;
size_t align;
unsigned int heap_id_mask;
unsigned int flags;
struct ion_handle *handle;
};
struct ion_fd_data {
struct ion_handle *handle;
int fd;
};
struct ion_custom_data {
unsigned int cmd;
unsigned long arg;
};
typedef struct ion_alloc_info {
uint32_t size;
struct ion_handle *handle;
int fd;
void* padd;
void* vadd;
} ion_alloc_info_t;
typedef struct {
int x;
int y;
unsigned int width;
unsigned int height;
} disp_rect;
typedef struct {
unsigned int width;
unsigned int height;
} disp_rectsz;
typedef enum tag_DISP_CMD {
DISP_RESERVE0 = 0x00,
DISP_RESERVE1 = 0x01,
DISP_SET_BKCOLOR = 0x03,
DISP_GET_BKCOLOR = 0x04,
DISP_SET_COLORKEY = 0x05,
DISP_GET_COLORKEY = 0x06,
DISP_GET_SCN_WIDTH = 0x07,
DISP_GET_SCN_HEIGHT = 0x08,
DISP_GET_OUTPUT_TYPE = 0x09,
DISP_SET_EXIT_MODE = 0x0A,
DISP_VSYNC_EVENT_EN = 0x0B,
DISP_BLANK = 0x0C,
DISP_SHADOW_PROTECT = 0x0D,
DISP_HWC_COMMIT = 0x0E,
DISP_DEVICE_SWITCH = 0x0F,
DISP_GET_OUTPUT = 0x10,
DISP_SET_COLOR_RANGE = 0x11,
DISP_GET_COLOR_RANGE = 0x12,
DISP_LAYER_ENABLE = 0x40,
DISP_LAYER_DISABLE = 0x41,
DISP_LAYER_SET_INFO = 0x42,
DISP_LAYER_GET_INFO = 0x43,
DISP_LAYER_TOP = 0x44,
DISP_LAYER_BOTTOM = 0x45,
DISP_LAYER_GET_FRAME_ID = 0x46,
DISP_LAYER_SET_CONFIG = 0x47,
DISP_LAYER_GET_CONFIG = 0x48,
DISP_HDMI_SUPPORT_MODE = 0xc4,
DISP_SET_TV_HPD = 0xc5,
DISP_HDMI_GET_EDID = 0xc6,
DISP_LCD_ENABLE = 0x100,
DISP_LCD_DISABLE = 0x101,
DISP_LCD_SET_BRIGHTNESS = 0x102,
DISP_LCD_GET_BRIGHTNESS = 0x103,
DISP_LCD_BACKLIGHT_ENABLE = 0x104,
DISP_LCD_BACKLIGHT_DISABLE = 0x105,
DISP_LCD_SET_SRC = 0x106,
DISP_LCD_SET_FPS = 0x107,
DISP_LCD_GET_FPS = 0x108,
DISP_LCD_GET_SIZE = 0x109,
DISP_LCD_GET_MODEL_NAME = 0x10a,
DISP_LCD_SET_GAMMA_TABLE = 0x10b,
DISP_LCD_GAMMA_CORRECTION_ENABLE = 0x10c,
DISP_LCD_GAMMA_CORRECTION_DISABLE = 0x10d,
DISP_LCD_USER_DEFINED_FUNC = 0x10e,
DISP_LCD_CHECK_OPEN_FINISH = 0x10f,
DISP_LCD_CHECK_CLOSE_FINISH = 0x110,
DISP_CAPTURE_START = 0x140,
DISP_CAPTURE_STOP = 0x141,
DISP_CAPTURE_COMMIT = 0x142,
DISP_ENHANCE_ENABLE = 0x180,
DISP_ENHANCE_DISABLE = 0x181,
DISP_ENHANCE_GET_EN = 0x182,
DISP_ENHANCE_SET_WINDOW = 0x183,
DISP_ENHANCE_GET_WINDOW = 0x184,
DISP_ENHANCE_SET_MODE = 0x185,
DISP_ENHANCE_GET_MODE = 0x186,
DISP_ENHANCE_DEMO_ENABLE = 0x187,
DISP_ENHANCE_DEMO_DISABLE = 0x188,
DISP_SMBL_ENABLE = 0x200,
DISP_SMBL_DISABLE = 0x201,
DISP_SMBL_GET_EN = 0x202,
DISP_SMBL_SET_WINDOW = 0x203,
DISP_SMBL_GET_WINDOW = 0x204,
DISP_FB_REQUEST = 0x280,
DISP_FB_RELEASE = 0x281,
DISP_MEM_REQUEST = 0x2c0,
DISP_MEM_RELEASE = 0x2c1,
DISP_MEM_GETADR = 0x2c2,
} __DISP_t;
typedef enum {
DISP_FORMAT_ARGB_8888 = 0x00,
DISP_FORMAT_ABGR_8888 = 0x01,
DISP_FORMAT_RGBA_8888 = 0x02,
DISP_FORMAT_BGRA_8888 = 0x03,
DISP_FORMAT_XRGB_8888 = 0x04,
DISP_FORMAT_XBGR_8888 = 0x05,
DISP_FORMAT_RGBX_8888 = 0x06,
DISP_FORMAT_BGRX_8888 = 0x07,
DISP_FORMAT_RGB_888 = 0x08,
DISP_FORMAT_BGR_888 = 0x09,
DISP_FORMAT_RGB_565 = 0x0a,
DISP_FORMAT_BGR_565 = 0x0b,
DISP_FORMAT_ARGB_4444 = 0x0c,
DISP_FORMAT_ABGR_4444 = 0x0d,
DISP_FORMAT_RGBA_4444 = 0x0e,
DISP_FORMAT_BGRA_4444 = 0x0f,
DISP_FORMAT_ARGB_1555 = 0x10,
DISP_FORMAT_ABGR_1555 = 0x11,
DISP_FORMAT_RGBA_5551 = 0x12,
DISP_FORMAT_BGRA_5551 = 0x13,
DISP_FORMAT_YUV444_I_AYUV = 0x40,
DISP_FORMAT_YUV444_I_VUYA = 0x41,
DISP_FORMAT_YUV422_I_YVYU = 0x42,
DISP_FORMAT_YUV422_I_YUYV = 0x43,
DISP_FORMAT_YUV422_I_UYVY = 0x44,
DISP_FORMAT_YUV422_I_VYUY = 0x45,
DISP_FORMAT_YUV444_P = 0x46,
DISP_FORMAT_YUV422_P = 0x47,
DISP_FORMAT_YUV420_P = 0x48,
DISP_FORMAT_YUV411_P = 0x49,
DISP_FORMAT_YUV422_SP_UVUV = 0x4a,
DISP_FORMAT_YUV422_SP_VUVU = 0x4b,
DISP_FORMAT_YUV420_SP_UVUV = 0x4c,
DISP_FORMAT_YUV420_SP_VUVU = 0x4d,
DISP_FORMAT_YUV411_SP_UVUV = 0x4e,
DISP_FORMAT_YUV411_SP_VUVU = 0x4f,
} disp_pixel_format;
typedef enum {
DISP_BT601 = 0,
DISP_BT709 = 1,
DISP_YCC = 2,
} disp_color_space;
typedef enum {
LAYER_MODE_BUFFER = 0,
LAYER_MODE_COLOR = 1,
} disp_layer_mode;
typedef enum {
DISP_3D_OUT_MODE_CI_1 = 0x5,
DISP_3D_OUT_MODE_CI_2 = 0x6,
DISP_3D_OUT_MODE_CI_3 = 0x7,
DISP_3D_OUT_MODE_CI_4 = 0x8,
DISP_3D_OUT_MODE_LIRGB = 0x9,
DISP_3D_OUT_MODE_TB = 0x0,
DISP_3D_OUT_MODE_FP = 0x1,
DISP_3D_OUT_MODE_SSF = 0x2,
DISP_3D_OUT_MODE_SSH = 0x3,
DISP_3D_OUT_MODE_LI = 0x4,
DISP_3D_OUT_MODE_FA = 0xa,
} disp_3d_out_mode;
typedef enum {
DISP_BF_NORMAL = 0,
DISP_BF_STEREO_TB = 1 << 0,
DISP_BF_STEREO_FP = 1 << 1,
DISP_BF_STEREO_SSH = 1 << 2,
DISP_BF_STEREO_SSF = 1 << 3,
DISP_BF_STEREO_LI = 1 << 4,
} disp_buffer_flags;
typedef enum {
DISP_SCAN_PROGRESSIVE = 0,
DISP_SCAN_INTERLACED_ODD_FLD_FIRST = 1 << 0,
DISP_SCAN_INTERLACED_EVEN_FLD_FIRST = 1 << 1,
} disp_scan_flags;
typedef struct {
long long x;
long long y;
long long width;
long long height;
} disp_rect64;
typedef struct {
unsigned long long addr[3];
disp_rectsz size[3];
unsigned int align[3];
disp_pixel_format format;
disp_color_space color_space;
unsigned int trd_right_addr[3];
bool pre_multiply;
disp_rect64 crop;
disp_buffer_flags flags;
disp_scan_flags scan;
} disp_fb_info;
typedef struct {
disp_layer_mode mode;
unsigned char zorder;
unsigned char alpha_mode;
unsigned char alpha_value;
disp_rect screen_win;
bool b_trd_out;
disp_3d_out_mode out_trd_mode;
union {
unsigned int color;
disp_fb_info fb;
};
unsigned int id;
} disp_layer_info;
typedef struct {
disp_layer_info info;
bool enable;
unsigned int channel;
unsigned int layer_id;
} disp_layer_config;
static int fb_dev = -1;
static int ion_dev = -1;
static int mem_dev = -1;
static int disp_dev = -1;
static uint32_t *mem_map = NULL;
static disp_layer_config fb_config={0};
static disp_layer_config buffer_config={0};
static ion_alloc_info_t buffer_info={0};
static int ion_alloc(int ion_fd, ion_alloc_info_t* info)
{
struct ion_allocation_data iad;
struct ion_fd_data ifd;
struct ion_custom_data icd;
sunxi_phys_data spd;
iad.len = info->size;
iad.align = sysconf(_SC_PAGESIZE);
iad.heap_id_mask = ION_HEAP_TYPE_DMA_MASK;
iad.flags = 0;
if (ioctl(ion_fd, ION_IOC_ALLOC, &iad) < 0) {
printf("failed to call ION_IOC_ALLOC\n");
return -1;
}
icd.cmd = ION_IOC_SUNXI_PHYS_ADDR;
icd.arg = (uintptr_t)&spd;
spd.handle = iad.handle;
if (ioctl(ion_fd, ION_IOC_CUSTOM, &icd) < 0) {
printf("failed to call ION_IOC_CUSTOM\n");
return -1;
}
ifd.handle = iad.handle;
if (ioctl(ion_fd, ION_IOC_MAP, &ifd) < 0) {
printf("failed to call ION_IOC_MAP\n");
}
info->handle = iad.handle;
info->fd = ifd.fd;
info->padd = (void*)spd.phys_addr;
info->vadd = mmap(0, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->fd, 0);
printf("allocated padd: 0x%x vadd: 0x%x size: 0x%x\n", (uintptr_t)info->padd, (uintptr_t)info->vadd, info->size);
return 0;
}
static void ion_free(int ion_fd, ion_alloc_info_t* info)
{
struct ion_handle_data ihd;
munmap(info->vadd, info->size);
close(info->fd);
ihd.handle = info->handle;
if (ioctl(ion_fd, ION_IOC_FREE, &ihd) < 0) {
printf("failed to call ION_ION_FREE\n");
}
}
static int fb_init(void)
{
int r = 0;
fb_dev = open("/dev/fb0", O_RDWR);
ion_dev = open("/dev/ion", O_RDWR);
mem_dev = open("/dev/mem", O_RDWR);
disp_dev = open("/dev/disp", O_RDWR);
if (fb_dev < 0) {
printf("failed to open /dev/fb0\n");
return -1;
}
memset(&fb_config, 0, sizeof(disp_layer_config));
memset(&buffer_config, 0, sizeof(disp_layer_config));
mem_map = mmap(0, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED, mem_dev, OVL_V);
ioctl(fb_dev, FBIO_WAITFORVSYNC, &r);
uint32_t args[4] = {0, (uintptr_t)&fb_config, 1, 0};
fb_config.channel = DEF_FB_CH;
fb_config.layer_id = DEF_FB_LAYER;
ioctl(disp_dev, DISP_LAYER_GET_CONFIG, args);
fb_config.enable = 0;
ioctl(disp_dev, DISP_LAYER_SET_CONFIG, args);
buffer_info.size = 320 * 240 * 2 * 2;
ion_alloc(ion_dev, &buffer_info);
buffer_config.channel = SCALER_CH;
buffer_config.layer_id = SCALER_LAYER;
buffer_config.enable = 1;
buffer_config.info.fb.format = DISP_FORMAT_RGB_565;
buffer_config.info.fb.addr[0] = (uintptr_t)buffer_info.padd;
buffer_config.info.fb.size[0].width = 240;
buffer_config.info.fb.size[0].height = 320;
buffer_config.info.mode = LAYER_MODE_BUFFER;
buffer_config.info.zorder = SCALER_ZORDER;
buffer_config.info.alpha_mode = 0;
buffer_config.info.alpha_value = 0;
buffer_config.info.screen_win.x = 0;
buffer_config.info.screen_win.y = 0;
buffer_config.info.screen_win.width = 240;
buffer_config.info.screen_win.height = 320;
buffer_config.info.fb.pre_multiply = 0;
buffer_config.info.fb.crop.x = (uint64_t)0 << 32;
buffer_config.info.fb.crop.y = (uint64_t)0 << 32;
buffer_config.info.fb.crop.width = (uint64_t)240 << 32;
buffer_config.info.fb.crop.height = (uint64_t)320 << 32;
args[1] = (uintptr_t)&buffer_config;
ioctl(disp_dev, DISP_LAYER_SET_CONFIG, args);
ioctl(fb_dev, FBIO_WAITFORVSYNC, &r);
return 0;
}
static int fb_uninit(void)
{
fb_config.enable = buffer_config.enable = 0;
uint32_t args[4] = {0, (uintptr_t)&fb_config, 1, 0};
ioctl(disp_dev, DISP_LAYER_SET_CONFIG, args);
args[1] = (uintptr_t)&buffer_config;
ioctl(disp_dev, DISP_LAYER_SET_CONFIG, args);
fb_config.enable = 1;
fb_config.channel = DEF_FB_CH;
fb_config.layer_id = DEF_FB_LAYER;
args[1] = (uintptr_t)&fb_config;
ioctl(disp_dev, DISP_LAYER_SET_CONFIG, args);
ion_free(ion_dev, &buffer_info);
munmap(mem_map, sysconf(_SC_PAGESIZE));
close(fb_dev);
close(ion_dev);
close(mem_dev);
close(disp_dev);
fb_dev = -1;
ion_dev = -1;
mem_dev = -1;
disp_dev = -1;
return 0;
}
int main(int argc, char **argv)
{
uint16_t *p = NULL;
uint16_t col[] = {0xf800, 0x07e0, 0x001f};
int cc = 0, x = 0, y = 0, r = 0, csel = 0;
uint32_t args[4] = {0, (uintptr_t)&buffer_config, 1, 0};
fb_init();
// x: 0~50
// y: 0~100
buffer_config.info.fb.crop.width = (uint64_t)50 << 32;
buffer_config.info.fb.crop.height = (uint64_t)100 << 32;
ioctl(disp_dev, DISP_LAYER_SET_CONFIG, args);
while (1) {
buffer_config.info.fb.addr[0] = (uintptr_t)((uint16_t*)buffer_info.padd + (320 * 240 * cc));
mem_map[OVL_V_TOP_LADD0 / 4] = (uintptr_t)((uint16_t*)buffer_info.padd + (320 * 240 * cc));
p = (uint16_t*)buffer_info.vadd + (320 * 240 * cc);
for (y=0; y<240; y++) {
for (x=0; x<320; x++) {
p[(((320 - 1) - x) * 240) + y] = col[(y / 80) % 3];
}
}
ioctl(fb_dev, FBIO_WAITFORVSYNC, &r);
cc^= 1;
csel+= 1;
usleep(3000000);
}
fb_uninit();
return 0;
}