关于OTA升级动画分屏策略的探索

2018-02-12  本文已影响69人  Ed_Lannister

本文为探索在recovery模式进行UI分屏的研究
    OTA升级过程中,流程是先将UI元素通过LoadBitmap的方式,读到对应的surface中,将各个surface画到一个绘制buffer里面,因为这里是需要做双眼分屏方案,故而buffer为半个屏幕大小。画好绘制buffer之后将绘制buffer以拷贝的方式,刷到显示buffer上去。
    初期的方案是在graphics_fbdev.cpp中的page_flip中加入合适的刷新方式,从而将绘制好的gr_draw通过memcpy的方式刷到显示buffer framebuffer[displayed]上去。
    但是这种方式存在一个问题,也就是本文主要解决的一个bug,这个问题就是,gr_draw是 Horizontal的方式进行读取的,而目标显示是横屏的(图形的方向是“^” ,“^”绘制进去就是“<”,因此需要将图像先右旋90度“>”.这样通过刷新就可以正常显示)这也是memcpy函数采用了将gr_draw的第j行第i列的像素copy到gr_framebuffer[displayed]的第i行的第w2-j-(w2-gr_draw->height)/2个像素了,其中(w2-gr_draw->height)是裁去了屏幕的多余的部分,因为屏幕是w2160h3840的横向显示屏,半屏大小是21601920,这里绘制buffer取的是1920*1920的正方形区域,实际上旋转对是否是正方形没有要求,满足Aij=Bj(n-i-1)即可。
    这样处理存在一个问题,每一次进行flip切换显示buffer时候,因为这里是通过双循环的方式去做memcpy,效率极其低下,没切换一帧耗时200ms。导致绘制的UI极其卡顿。

+LOCAL_CFLAGS += -DDUALEYE_SQUARE
+#ifdef DUALEYE_SQUARE
+       gr_draw = (GRSurface*) malloc(sizeof(GRSurface));
+        memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
+
+       gr_draw->height=min(gr_draw->height/2,gr_draw->width);
+       gr_draw->width=gr_draw->height;
+       gr_draw->row_bytes=(gr_draw->row_bytes*gr_draw->width)/gr_framebuffer[0].width;
+        gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes);
+        if (!gr_draw->data) {
+            perror("failed to allocate in-memory surface");
+            return NULL;
+        }
+
+#else
         gr_draw = gr_framebuffer+1;
+#endif

+#ifdef DUALEYE_SQUARE
+       int i,j;
+       int w2,h2;
+       w2=gr_framebuffer[0].width;
+       for(i=0;i<gr_draw->width;i++)
+               for(j=0;j<gr_draw->height;j++)
+               {
+                       int x1 = w2-j-(w2-gr_draw->height)/2;
+                       int y1 = i;
+                       int x2 = x1;
+                       int y2=i+gr_framebuffer[0].height/2;
+                       //rotate 90degree for left eye
+                       memcpy(gr_framebuffer[displayed_buffer].data+y1*gr_framebuffer[0].row_bytes+x1*gr_framebuffer[0].pixel_bytes,
+                                       gr_draw->data+j*gr_draw->row_bytes+i*gr_framebuffer[0].pixel_bytes,
+                                               gr_framebuffer[0].pixel_bytes);
+
+                       //rotate 90degree for right eye
+                       memcpy(gr_framebuffer[displayed_buffer].data+y2*gr_framebuffer[0].row_bytes+x2*gr_framebuffer[0].pixel_bytes,
+                                       gr_draw->data+j*gr_draw->row_bytes+i*gr_framebuffer[0].pixel_bytes,
+                                               gr_framebuffer[0].pixel_bytes);
+               }
+#else
         gr_draw = gr_framebuffer + displayed_buffer;
+#endif

static void fbdev_exit(minui_backend* backend __unused) {
         free(gr_draw->data);
         free(gr_draw);
     }
+
+#ifdef DUALEYE_SQUARE
+    if (gr_draw) {
+        free(gr_draw->data);
+        free(gr_draw);
+    }
+#endif
     gr_draw = NULL;
 }

    为了解决这个问题,采取很多的尝试,首先尝试了去改写memcpy函数,通过采取按int型读取的方式,相当于四字节一次的拷贝,因为原有的数据结构是如下结构,结构体的数据是char型指针,每次偏移的是一个字符的地址,虽然设定的步长是gr_framebuffer[0].pixel_bytes,该值为4,相当于嵌套三次的循环,如果修改memcpy函数,让其按int型指针,一次取4个字节,可能能提升4倍的速度。这里基于的知识是,按字节memcpy和按int型memcpy的速度不一样,后面证实,cpy方式确实会影响速率。

struct GRSurface {
    int width;
    int height;
    int row_bytes;
    int pixel_bytes;
    unsigned char* data;
};

    memcpy函数修改,但是通过实际测试,效果并没有多大提升。

 void *memcpy(void *dest, const void *src, size_t n)
{
  int *d = (int *) dest
  const int *s = (const int *) src;
  while (n--)
  *d++ = *s++;
  value = 1;
  return dest;
}

    然后同时又根据刷新效率的考量,修改了如下方式,让memcpy按行刷新,代码如下。这里刷新效率大为提升,但是没有做旋转的工作,导致这里画面显示方向为“<”。因为采用的是一层循环,算法复杂度为f(n)。这里考虑了一下,如果想要将刷新和旋转一起做,必须至少是按int型四像素一起copy,或者是按像素拷贝,效率目前来看都是无法提升的。所以,关注点,改为放到了绘制阶段,将图绘制到gr_draw上面的时候就直接画成">"这个方向。

int y1 = gr_framebuffer[0].height/2;
    for(int i=0;i<gr_draw->width;i++){
    //rotate 90degree for left eye
        memcpy(gr_framebuffer[displayed_buffer].data+i*gr_framebuffer[0].row_bytes,
                    gr_draw->data+i*gr_draw->row_bytes,
                        gr_draw->row_bytes);

    //rotate 90degree for right eye
        memcpy(gr_framebuffer[displayed_buffer].data+(i+y1)*gr_framebuffer[0].row_bytes,
                    gr_draw->data+i*gr_draw->row_bytes,
                        gr_draw->row_bytes);
    }

    这里就需要将所有元素变成竖向的资源,这里只用在图片查看器里面进行一下旋转然后保存即可。然后调整刷新方式,让绘制函数按照新的刷新方式,新的目标位置进行刷新。修改内容如下。

 int ScreenRecoveryUI::GetAnimationBaseline() {
-    return GetTextBaseline() - PixelsFromDp(kLayouts[layout_][ICON]) -
+    return GetTextBaseline() - PixelsFromDp(120) -
             gr_get_height(loopFrames[0]);
 }
 
 int ScreenRecoveryUI::GetTextBaseline() {
-    return GetProgressBaseline() - PixelsFromDp(kLayouts[layout_][TEXT]) -
+    return GetProgressBaseline() - PixelsFromDp(32) -
             gr_get_height(installing_text);
 }
 
 int ScreenRecoveryUI::GetProgressBaseline() {
-    return gr_fb_height() - PixelsFromDp(kLayouts[layout_][PROGRESS]) -
+    return gr_fb_width() - PixelsFromDp(833) -
             gr_get_height(progressBarFill);
 }
 
@@ -163,8 +163,8 @@
         }
 
         GRSurface* text_surface = GetCurrentText();
-        int text_x = (gr_fb_width() - gr_get_width(text_surface)) / 2;
-        int text_y = GetTextBaseline();
+        int text_x = 900;
+        int text_y = (gr_fb_width() - gr_get_height(text_surface)) / 2;
         gr_color(255, 255, 255, 255);
         gr_texticon(text_x, text_y, text_surface);
     }
@@ -178,25 +178,24 @@
         GRSurface* frame = GetCurrentFrame();
         int frame_width = gr_get_width(frame);
         int frame_height = gr_get_height(frame);
-        int frame_x = (gr_fb_width() - frame_width) / 2;
-        int frame_y = GetAnimationBaseline();
-        gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
+        int frame_x = gr_fb_width() - gr_get_width(frame)-299;
+        int frame_y = (gr_fb_width()-gr_get_width(frame))/2;
+   gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
     }
 
     if (progressBarType != EMPTY) {
         int width = gr_get_width(progressBarEmpty);
         int height = gr_get_height(progressBarEmpty);
 
-        int progress_x = (gr_fb_width() - width)/2;
-        int progress_y = GetProgressBaseline();
-
+        int progress_x = (gr_fb_width() - 368)/2;
+        int progress_y = (gr_fb_width()-gr_get_height(progressBarEmpty))/2;
         // Erase behind the progress bar (in case this was a progress-only update)
         gr_color(0, 0, 0, 255);
         gr_fill(progress_x, progress_y, width, height);
 
         if (progressBarType == DETERMINATE) {
             float p = progressScopeStart + progress * progressScopeSize;
-            int pos = (int) (p * width);
+            int pos = (int) (p * height);
 
             if (rtl_locale) {
                 // Fill the progress bar from right to left.
@@ -210,11 +209,10 @@
             } else {
                 // Fill the progress bar from left to right.
                 if (pos > 0) {
-                    gr_blit(progressBarFill, 0, 0, pos, height, progress_x, progress_y);
+                    gr_blit(progressBarFill, 0, 0, width, pos, progress_x, progress_y);
                 }
-                if (pos < width-1) {
-                    gr_blit(progressBarEmpty, pos, 0, width-pos, height,
-                            progress_x+pos, progress_y);
+                if (pos < height-1) {
+                    gr_blit(progressBarEmpty, 0, pos, width, height-pos,progress_x, progress_y+pos);
                 }
             }
         }

    唯一不同是升级文字,这里文字采取的方式是,通过读取地点local=Zn_ch,然后去读install_text.PNG资源,这里只分析一下如下代码,通过新建一个row型指针,因为install_text有很多行的各国语言的资源。逐行通过png_read_row去从图片中取数据放到row所指向的区域。通过row[1]的左移8位与row[0]的按位或得到文字的宽度,同样的方式处理2.3得到文字的高度,row[5]里面存放的是属于哪国的语言。如果超出范围或者语言和地区匹配则进入循环,这里新建了一个surface用来存放读取出来的图片。这里由于图片比较小,采用双循环的方式,对图片进行左旋90度。将旋转后的surface送到输出surface指针中。

row = reinterpret_cast<unsigned char*>(malloc(width));
    for (y = 0; y < height; ++y) {
        png_read_row(png_ptr, row, NULL);
        int w = (row[1] << 8) | row[0];
        int h = (row[3] << 8) | row[2];
        int len = row[4];
        char* loc = (char*)row+5;
         if (y+1+h >= height || matches_locale(loc, locale)) {
-            printf("  %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
-
-            surface = malloc_surface(w*h);
+            printf("match success name=%20s: loc=%20s ;locale=%s ;(w = %d x h = %d @ y =%d)\n", name, loc, locale,w, h, y);
+            surface = malloc_surface(h*w);
             if (surface == NULL) {
                 result = -8;
                 goto exit;
             }
-            surface->width = w;
-            surface->height = h;
+            surface->width = h;
+            surface->height = w;
             surface->row_bytes = w;
             surface->pixel_bytes = 1;
 
-            int i;
-            for (i = 0; i < h; ++i, ++y) {
+            for (int i = 0; i < h; ++i, ++y) {
                 png_read_row(png_ptr, row, NULL);
-                memcpy(surface->data + i*w, row, w);
+                for(int j =0; j< w; ++j){
+                memcpy(surface->data+j*surface->row_bytes+(h-i)*surface->pixel_bytes,
+                                    &row[j],
+                                    1);
+                }
             }
-
             *pSurface = reinterpret_cast<GRSurface*>(surface);
             break;
         } else {
上一篇 下一篇

猜你喜欢

热点阅读