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; }