全志G2D实现屏幕旋转,开机logo实现手动旋转。

  • 全志G2D实现屏幕旋转,开机logo实现手动旋转。已关闭评论
  • 116 次浏览
  • A+
所属分类:linux技术
摘要

产品设计出来之后啊,大家使用的时候觉得反过来使用更加便捷。但是屏幕显示是反的。 那怎么办那?????

产品设计出来之后啊,大家使用的时候觉得反过来使用更加便捷。但是屏幕显示是反的。那怎么办那?????

修改硬件费时费工,那能否软件实现那?????

 如果纯软件使用那就太费系统资源了。于是就想到了使用全志R528 自带的G2D功能(硬件加速功能)。

使用它进行旋转,后又发现uboot阶段系统没有G2D导致开机logo不能自动旋转,内核启动后G2D 启动logo 又旋转了。

(好烦啊!!!!!!!!!!!!)

于是就需要把uboot 阶段手动把图片数据旋转过来。在G2D启动前把uboot 传递给内核的logo 图片数据也旋转过来。

下面具体步骤:

一、开启G2D功能。

1、由于此前公版默认在modules.mk屏蔽了屏旋转相关配置, 如果你的版本是禁用旋转的, 需要把相关配置去掉.
device/config/chips/r528/configs/evb1/linux-5.4/config-5.4

2759:# CONFIG_SUNXI_DISP2_FB_DISABLE_ROTATE is not set
以下3个相关选项

CONFIG_DISP2_SUNXI=m  #CONFIG_SUNXI_DISP2_FB_DISABLE_ROTATE=y  #CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT=n  #CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT=n 
修改为:
CONFIG_DISP2_SUNXI=m  #CONFIG_SUNXI_DISP2_FB_DISABLE_ROTATE=n  #CONFIG_SUNXI_DISP2_FB_ROTATION_SUPPORT=n  #CONFIG_SUNXI_DISP2_FB_HW_ROTATION_SUPPORT=y 

 

2、硬件旋转需要确保G2D驱动已经使能

make kernel_menuconfig Device Drivers ---> <*> SUNXI G2D Driver [*] sunxi g2d mixer module [*] sunxi g2d rotate module [] sunxi sync fence implement for rotate jobs synchronous

3.打开显示驱动旋转支持

make kernel_menuconfig Device Drivers ---> Graphics support ---> Frame buffer Devices ---> Video support for sunxi ---> DISP2 Framebuffer rotation support (Disable rotation) ---> ( ) Disable rotation ( ) Software rotation support (不要选这个,方案未支持) (X) Hardware(G2D) rotation support (选择G2D旋转)

4.dts配置

 

board.dts 和 uboot-board.dts同步修改.

&disp{ ..... disp_rotation_used = <1>;/* 使能旋转功能 */ degree0 = <2>; /* X:screen index; 0:0 degree; 1:90 degree; 3:270 degree */ fb0_width = <800>;/*fb 的长宽交换*/ fb0_height = <480>; ..... };

 

5.旋转后framebuffer编程是需要注意,旋转后的buffer不会直接显示到屏幕上, 需要在应用刷屏的地方调用FBIOPAN_DISPLAY接口.同步旋转后的buffer到LCD上.

 

以修改公版旋转的GUI刷屏示例:

 

路径:package/gui/littlevgl-6/lv_drivers/display/fbdev.c  void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p){ ....     lv_disp_flush_ready(drv);     ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo); /*函数最后,在刷屏函数后面,调用 FBIOPAN_DISPLAY 接口*/ }

 

我们系统时自己的UI系统。是在重绘回调函数中,增加FBIOPAN_DISPLAY

 

 

main()
{
int fp=0; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; fp = open("/dev/fb0", O_RDWR); if(fp < 0) { printf("Error : Can not open framebuffer device/n"); exit(1); } if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){ printf("Error reading variable information/n"); exit(3); } vinfo.xoffset = 0; vinfo.yoffset = 0;
}
void sys_paint(void) // 每次重绘调用一次 {   ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo); /*函数最后,在刷屏函数后面,调用 FBIOPAN_DISPLAY 接口*/ }

二、uboot阶段手动修改旋转图片数据

  追踪uboot  logo 执行过程

static int run_main_loop(void)   { ....     #ifdef CONFIG_ARCH_SUNXI         initr_sunxi_plat,     #endif .... }  initr_sunxi_plat { ....               #ifdef CONFIG_BOOT_GUI                 void board_bootlogo_display(void);                 board_bootlogo_display();         #else .... }  void board_bootlogo_display(void)  { .... #if defined(CONFIG_CMD_SUNXI_BMP)     sunxi_bmp_display("bootlogo.bmp"); //指定bootlogo的名字。通过修改这个地方可以修改指定logo的名称      #elif defined(CONFIG_CMD_SUNXI_JPEG)     sunxi_jpeg_display("bootlogo.jpg"); #endif     .... }   int sunxi_bmp_display(char *name) {     int ret = -1;     char *argv[6];     char bmp_head[32];273     char bmp_name[32];     char part_info[16] = {0};     char size[32] = {0};     int partno = -1;     unsigned long file_size = 0;     char *bmp_head_addr;     struct bmp_image *bmp;     bmp = memalign(CONFIG_SYS_CACHELINE_SIZE,  ALIGN(sizeof(struct bmp_header), CONFIG_SYS_CACHELINE_SIZE));     if (bmp) {         sprintf(bmp_head, "%lx", (ulong)bmp);     } else {         pr_error("sunxi bmp: alloc buffer for %s failn", name);         goto out;     }     partno = sunxi_partition_get_partno_byname("bootloader"); /*android*/     if (partno < 0) {         partno = sunxi_partition_get_partno_byname(             "boot-resource"); /*linux*/         if (partno < 0) {             pr_error("Get bootloader and boot-resource partition number fail!n");             goto free1;         }     }     snprintf(part_info, 16, "0:%x", partno);     strncpy(bmp_name, name, sizeof(bmp_name));     snprintf(size, 16, "%lx", (ulong)sizeof(struct bmp_header));      argv[0] = "fatload";     argv[1] = "sunxi_flash";     argv[2] = part_info;     argv[3] = bmp_head;     argv[4] = bmp_name;     argv[5] = size;      if (do_fat_fsload(0, 0, 6, argv)) {         pr_error("sunxi bmp info error : unable to open logo file %sn",                argv[4]);         goto free1;     }     if ((bmp->header.signature[0] != 'B') ||         (bmp->header.signature[1] != 'M')) {         pr_error("this is not a bmp picturen");         goto free1;     }     file_size = bmp->header.file_size;      bmp_head_addr = memalign(CONFIG_SYS_CACHELINE_SIZE,  ALIGN(file_size, CONFIG_SYS_CACHELINE_SIZE));     if (bmp_head_addr) {         sprintf(bmp_head, "%lx", (ulong)bmp_head_addr);     } else {         pr_error("sunxi bmp: alloc buffer for %s failn", name);         goto free1;     }      snprintf(size, 16, "%lx", (ulong)file_size);      tick_printf("bmp_name=%s size %ldn", bmp_name, file_size);      if (do_fat_fsload(0, 0, 6, argv)) {         pr_error("sunxi bmp info error : unable to open logo file %sn",                argv[4]);         goto free2;     }  //在调用show_bmp_on_fb 之前将bmp_head_addr中的图片数据进行旋转

  // 调用旋转函数
  rotateBMP180(bmp_head_addr);

    ret = show_bmp_on_fb(bmp_head_addr, FB_ID_0);     if (ret != 0)         pr_error("show bmp on fb failed !%dn", ret);  free2:     free(bmp_head_addr); free1:     free(bmp); out:     return ret; }         

旋转函数:

主要发现uboot 阶段malloc不能申请太大的内存空间,所以代码中申请的行的大小。

#pragma pack(push, 1) typedef struct {     uint16_t type;     uint32_t size;     uint16_t reserved1;     uint16_t reserved2;     uint32_t offset; } BMPFileHeader; #pragma pack(pop)  // 定义BMP图像信息头结构体 #pragma pack(push, 1) typedef struct {     uint32_t header_size;     int32_t width;     int32_t height;     uint16_t planes;     uint16_t bit_count;     uint32_t compression;     uint32_t image_size;     int32_t x_pixels_per_meter;     int32_t y_pixels_per_meter;     uint32_t colors_used;     uint32_t colors_important; } BMPInfoHeader; #pragma pack(pop)   // 旋转BMP图像180度 void rotateBMP180(char * bmp_head_add) {     // 读取文件头     BMPFileHeader* file_header = (BMPFileHeader*)bmp_head_add;      // 读取图像信息头     BMPInfoHeader* info_header = (BMPInfoHeader*)(bmp_head_add + sizeof(BMPFileHeader));      // 获取图像宽度、高度和每行像素所占字节数     int32_t width = info_header->width;     int32_t height = info_header->height;     uint32_t row_size = (info_header->bit_count * width + 31) / 32 * 4;      // 创建临时缓冲区存储旋转后的图像数据     uint8_t* temp_data = (uint8_t*)malloc(row_size);     if (temp_data == NULL) {         printf("Failed to allocate memory for temporary data.n");         return;     }      // 旋转图像     for (int32_t row = 0; row < height / 2; ++row) {         for (int32_t col = 0; col < width; ++col) {             // 计算当前像素位置和对应的对称像素位置             int32_t original_index = row * row_size + col * 3;             int32_t symmetric_index = (height - 1 - row) * row_size + (width - 1 - col) * 3;              // 交换像素颜色值             uint8_t temp_red = bmp_head_add[file_header->offset + original_index];             uint8_t temp_green = bmp_head_add[file_header->offset + original_index + 1];             uint8_t temp_blue = bmp_head_add[file_header->offset + original_index + 2];              bmp_head_add[file_header->offset + original_index] = bmp_head_add[file_header->offset + symmetric_index];             bmp_head_add[file_header->offset + original_index + 1] = bmp_head_add[file_header->offset + symmetric_index + 1];             bmp_head_add[file_header->offset + original_index + 2] = bmp_head_add[file_header->offset + symmetric_index + 2];              bmp_head_add[file_header->offset + symmetric_index] = temp_red;             bmp_head_add[file_header->offset + symmetric_index + 1] = temp_green;             bmp_head_add[file_header->offset + symmetric_index + 2] = temp_blue;         }     }      // 释放临时缓冲区内存     free(temp_data); }

 

三、kernel阶段手动修改旋转logo图片数据

  追踪内核执行过程

disp_module_init{ ........     platform_driver_unregister(&disp_driver); #ifndef CONFIG_OF     platform_device_unregister(&disp_device); #endif ........  }   static int disp_probe(struct platform_device *pdev){ ........         bsp_disp_init(para); ........ }   static s32 disp_init(struct platform_device *pdev)     { ........     lcd_init();     bsp_disp_open();      fb_init(pdev); ........  }  s32 fb_init(struct platform_device *pdev) { ........     ret = display_fb_request(i, &fb_para); ........ }  static s32 display_fb_request(u32 fb_id, struct disp_fb_create_info *fb_para) { ........     Fb_map_kernel_logo(sel, info); ........ }  static int Fb_map_kernel_logo(u32 sel, struct fb_info *info) { ........     paddr = bootlogo_addr;     if (paddr == 0) {         __inf("Fb_map_kernel_logo failed!");         return Fb_copy_boot_fb(sel, info);     } ........ }  static int Fb_copy_boot_fb(u32 sel, struct fb_info *info) {     enum {         BOOT_FB_ADDR = 0,         BOOT_FB_WIDTH,         BOOT_FB_HEIGHT,         BOOT_FB_BPP,         BOOT_FB_STRIDE,         BOOT_FB_CROP_L,         BOOT_FB_CROP_T,         BOOT_FB_CROP_R,         BOOT_FB_CROP_B,     };      char *boot_fb_str = NULL;     char *src_phy_addr = NULL;     char *src_addr = NULL;     char *src_addr_b = NULL;     char *src_addr_e = NULL;     int src_width = 0;     int src_height = 0;     int fb_height = 0;     int src_bpp = 0;     int src_stride = 0;     int src_cp_btyes = 0;     int src_crop_l = 0;     int src_crop_t = 0;     int src_crop_r = 0;     int src_crop_b = 0;      char *dst_addr = NULL;     int dst_width = 0;     int dst_height = 0;     int dst_bpp = 0;     int dst_stride = 0;     int ret;      unsigned long map_offset;      if (info == NULL) {         __wrn("%s,%d: null pointern", __func__, __LINE__);         return -1;     }      boot_fb_str = (char *)disp_boot_para_parse_str("boot_fb0");     if (boot_fb_str != NULL) {         int i = 0;         char boot_fb[128] = { 0 };         int len = strlen(boot_fb_str);          if (sizeof(boot_fb) - 1 < len) {             __wrn("need bigger array size[%d] for boot_fbn", len);             return -1;         }         memcpy((void *)boot_fb, (void *)boot_fb_str, len);         boot_fb[len] = '';         boot_fb_str = boot_fb;         for (i = 0;; ++i) {             char *p = strstr(boot_fb_str, ",");              if (p != NULL)                 *p = '';             if (i == BOOT_FB_ADDR) {                 ret = kstrtoul(boot_fb_str, 16,                     (unsigned long *)&src_phy_addr);                 if (ret)                     pr_warn("parse src_phy_addr fail!n");             } else if (i == BOOT_FB_WIDTH) {                 ret = kstrtou32(boot_fb_str, 16, &src_width);                 if (ret)                     pr_warn("parse src_width fail!n");             } else if (i == BOOT_FB_HEIGHT) {                 ret = kstrtou32(boot_fb_str, 16, &src_height);                 fb_height = src_height;                 if (ret)                     pr_warn("parse src_height fail!n");             } else if (i == BOOT_FB_BPP) {                 ret = kstrtou32(boot_fb_str, 16, &src_bpp);                 if (ret)                     pr_warn("parse src_bpp fail!n");             } else if (i == BOOT_FB_STRIDE) {                 ret = kstrtou32(boot_fb_str, 16, &src_stride);                 if (ret)                     pr_warn("parse src_stride fail!n");             } else if (i == BOOT_FB_CROP_L) {                 ret = kstrtou32(boot_fb_str, 16, &src_crop_l);                 if (ret)                     pr_warn("parse src_crop_l fail!n");             } else if (i == BOOT_FB_CROP_T) {                 ret = kstrtou32(boot_fb_str, 16, &src_crop_t);                 if (ret)                     pr_warn("parse src_crop_t fail!n");             } else if (i == BOOT_FB_CROP_R) {                 ret = kstrtou32(boot_fb_str, 16, &src_crop_r);                 if (ret)                     pr_warn("parse src_crop_r fail!n");             } else if (i == BOOT_FB_CROP_B) {                 ret = kstrtou32(boot_fb_str, 16, &src_crop_b);                 if (ret)                     pr_warn("parse src_crop_b fail!n");             } else {                 break;             }              if (p == NULL)                 break;             boot_fb_str = p + 1;         }     } else {         __wrn("no boot_fb0n");         return -1;     }      dst_addr = (char *)(info->screen_base);     dst_width = info->var.xres;     dst_height = info->var.yres;     dst_bpp = info->var.bits_per_pixel;     dst_stride = info->fix.line_length;      if ((src_phy_addr == NULL)         || (src_width <= 0)         || (src_height <= 0)         || (src_stride <= 0)         || (src_bpp <= 0)         || (dst_addr == NULL)         || (dst_width <= 0)         || (dst_height <= 0)         || (dst_stride <= 0)         || (dst_bpp <= 0)         || (src_bpp != dst_bpp)) {         __wrn             ("wrong para: src[phy_addr=%p,w=%d,h=%d,bpp=%d,stride=%d], dst[addr=%p,w=%d,h=%d,bpp=%d,stride=%d]n",              src_phy_addr,              src_width, src_height, src_bpp, src_stride, dst_addr,              dst_width, dst_height, dst_bpp, dst_stride);         return -1;     }      map_offset = (unsigned long)src_phy_addr + PAGE_SIZE         - PAGE_ALIGN((unsigned long)src_phy_addr + 1);     src_addr = (char *)Fb_map_kernel_cache((unsigned long)src_phy_addr -                            map_offset,                            src_stride * src_height +                            map_offset);     if (src_addr == NULL) {         __wrn("Fb_map_kernel_cache for src_addr failedn");         return -1;     }      src_addr_b = src_addr + map_offset;     if ((src_crop_b > src_crop_t) &&         (src_height > src_crop_b - src_crop_t) &&         (src_crop_t >= 0) &&         (src_height >= src_crop_b)) {         src_height = src_crop_b - src_crop_t;         src_addr_b += (src_stride * src_crop_t);     }     if ((src_crop_r > src_crop_l)         && (src_width > src_crop_r - src_crop_l)         && (src_crop_l >= 0)         && (src_width >= src_crop_r)) {         src_width = src_crop_r - src_crop_l;         src_addr_b += (src_crop_l * src_bpp >> 3);     }      // 旋转图片数据    // rotateImage180(src_addr_b, src_width, src_height, src_bpp, src_stride);              if (src_height < dst_height) {         int dst_crop_t = (dst_height - src_height) >> 1;          dst_addr += (dst_stride * dst_crop_t);     } else if (src_height > dst_height) {         __wrn("src_height(%d) > dst_height(%d),please cut the heightn",               src_height,               dst_height);         Fb_unmap_kernel(src_addr);         return -1;     }     if (src_width < dst_width) {         int dst_crop_l = (dst_width - src_width) >> 1;          dst_addr += (dst_crop_l * dst_bpp >> 3);     } else if (src_width > dst_width) {         __wrn("src_width(%d) > dst_width(%d),please cut the width!n",               src_width,               dst_width);         Fb_unmap_kernel(src_addr);         return -1;     }      src_cp_btyes = src_width * src_bpp >> 3;     src_addr_e = src_addr_b + src_stride * src_height;     for (; src_addr_b != src_addr_e; src_addr_b += src_stride) {         memcpy((void *)dst_addr, (void *)src_addr_b, src_cp_btyes);         dst_addr += dst_stride;     }        //再此地方旋转修改     dst_addr = (char *)(info->screen_base);     rotateImage180(dst_addr, dst_width, dst_height, dst_bpp, dst_stride);      Fb_unmap_kernel(src_addr);     memblock_free((unsigned long)src_phy_addr, src_stride * fb_height);     free_reserved_area(__va(src_phy_addr), __va(src_phy_addr + PAGE_ALIGN(src_stride * fb_height)), 0x00, "logo buffer");     return 0; }     

旋转180函数:

放在 tina-r528licheelinux-5.4driversvideofbdevsunxidisp2dispdev_fb.c

注意此处由于申请的内存空间比较大,所以用的是vmalloc

void rotateImage180(char* src_addr, int width, int height, int bpp, int stride) {                     // 计算每行像素数据的字节数     int row_bytes = width * (bpp / 8);         char * src_addr_e = src_addr + stride* height; //最后的地址位置      // 创建临时缓冲区用于保存旋转后的图像数据     char* temp_data = vmalloc(row_bytes * height);         int y=0,x=0;      // 复制旋转后的图像数据到临时缓冲区     for (y = 0; y < height; y++) {         char* src_row_start = src_addr + (y * stride);         char* dest_row_start = temp_data + ((height - 1 - y) * row_bytes);                 // 复制像素数据并进行左右翻转                         for ( x = 0; x < width; x++) {                                 char* src_pixel = src_row_start + (x * (bpp / 8));                                 char* dest_pixel = dest_row_start + ((width - 1 - x) * (bpp / 8));                                 // 复制像素值                                 memcpy(dest_pixel, src_pixel, (bpp / 8));                         }      }       //printk("----%s--%dn",__func__,__LINE__);         // 将旋转后的图像数据写回原始内存地址         for (; src_addr != src_addr_e; src_addr += stride) {  //循环复制每一行                 memcpy((void *)src_addr, (void *)temp_data, row_bytes);                 temp_data += row_bytes;  //地址是增加地址宽度         }         //printk("----%s--%dn",__func__,__LINE__);     // 释放临时缓冲区     vfree(temp_data); }

 

 

 参考资料:

(67条消息) uboot修改启动logo-sunxi_u-boot启动时改横屏_Chasing_Chasing的博客-CSDN博客

【FAQ】全志F133(D1s)芯片 如何在Tina下进行显示旋转? | 全志在线开发者论坛 (aw-ol.com)