Bug 831624 - Use fb/gralloc to render boot animation, r=cjones,joe,glennrp
authorMichael Wu <mwu@mozilla.com>
Thu, 24 Jan 2013 21:18:30 -0800
changeset 126025 358dd2a3299058e813a16760d41294fb6886bc46
parent 126024 818bfecbe8e58f538302e67e0da82041290223fc
child 126026 8edae7afe6b0dfdeca55e8b720546731f842a506
child 133974 8a3901221fd9bc9bb39e759f4a49bedffbaec287
push id3384
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:42:39 +0000
treeherdermozilla-aurora@d8c97bae8521 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones, joe, glennrp
bugs831624
milestone21.0a1
Bug 831624 - Use fb/gralloc to render boot animation, r=cjones,joe,glennrp
b2g/app/BootAnimation.cpp
b2g/app/Makefile.in
media/libpng/mozpngconf.h
--- a/b2g/app/BootAnimation.cpp
+++ b/b2g/app/BootAnimation.cpp
@@ -8,35 +8,32 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#include <GLES2/gl2.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
 #include <algorithm>
 #include <endian.h>
 #include <fcntl.h>
 #include <string>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <vector>
 #include "mozilla/FileUtils.h"
 #include "mozilla/NullPtr.h"
 #include "mozilla/Util.h"
 #include "png.h"
 
 #include "android/log.h"
 #include "ui/FramebufferNativeWindow.h"
 #include "hardware_legacy/power.h"
+#include "hardware/gralloc.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args)
 #define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args)
 
 using namespace android;
 using namespace mozilla;
 using namespace std;
@@ -227,19 +224,20 @@ public:
             return nullptr;
         return data;
     }
 };
 
 struct AnimationFrame {
     char path[256];
     char *buf;
-    uint16_t width;
-    uint16_t height;
     const local_file_header *file;
+    uint32_t width;
+    uint32_t height;
+    uint16_t bytepp;
 
     AnimationFrame() : buf(nullptr) {}
     AnimationFrame(const AnimationFrame &frame) : buf(nullptr) {
         strncpy(path, frame.path, sizeof(path));
         file = frame.file;
     }
     ~AnimationFrame()
     {
@@ -247,17 +245,17 @@ struct AnimationFrame {
             free(buf);
     }
 
     bool operator<(const AnimationFrame &other) const
     {
         return strcmp(path, other.path) < 0;
     }
 
-    void ReadPngFrame();
+    void ReadPngFrame(int outputFormat);
 };
 
 struct AnimationPart {
     int32_t count;
     int32_t pause;
     char path[256];
     vector<AnimationFrame> frames;
 };
@@ -276,18 +274,30 @@ RawReader(png_structp png_ptr, png_bytep
     RawReadState *state = (RawReadState *)png_get_io_ptr(png_ptr);
     if (length > (state->length - state->offset))
         png_err(png_ptr);
 
     memcpy(data, state->start + state->offset, length);
     state->offset += length;
 }
 
+static void
+TransformTo565(png_structp png_ptr, png_row_infop row_info, png_bytep data)
+{
+    uint16_t *outbuf = (uint16_t *)data;
+    uint8_t *inbuf = (uint8_t *)data;
+    for (int i = 0; i < row_info->rowbytes; i += 3) {
+        *outbuf++ = ((inbuf[i]     & 0xF8) << 8) |
+                    ((inbuf[i + 1] & 0xFC) << 3) |
+                    ((inbuf[i + 2]       ) >> 3);
+    }
+}
+
 void
-AnimationFrame::ReadPngFrame()
+AnimationFrame::ReadPngFrame(int outputFormat)
 {
     png_structp pngread = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                                  nullptr, nullptr, nullptr);
 
     png_infop pnginfo = png_create_info_struct(pngread);
 
     RawReadState state;
     state.start = file->GetData();
@@ -297,101 +307,91 @@ AnimationFrame::ReadPngFrame()
     png_set_read_fn(pngread, &state, RawReader);
 
     setjmp(png_jmpbuf(pngread));
 
     png_read_info(pngread, pnginfo);
 
     width = png_get_image_width(pngread, pnginfo);
     height = png_get_image_height(pngread, pnginfo);
-    buf = (char *)malloc(width * height * 3);
+    switch (outputFormat) {
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+        png_set_bgr(pngread);
+        // FALL THROUGH
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+        bytepp = 4;
+        png_set_filler(pngread, 0xFF, PNG_FILLER_AFTER);
+        break;
+    case HAL_PIXEL_FORMAT_RGB_888:
+        bytepp = 3;
+        png_set_strip_alpha(pngread);
+        break;
+    default:
+        LOGW("Unknown pixel format %d. Assuming RGB 565.", outputFormat);
+        // FALL THROUGH
+    case HAL_PIXEL_FORMAT_RGB_565:
+        bytepp = 2;
+        png_set_strip_alpha(pngread);
+        png_set_read_user_transform_fn(pngread, TransformTo565);
+        break;
+    }
+
+    // An extra row is added to give libpng enough space when
+    // decoding 3/4 bytepp inputs for 2 bytepp output surfaces
+    buf = (char *)malloc(width * (height + 1) * bytepp);
 
     vector<char *> rows(height + 1);
-    uint32_t stride = width * 3;
+    uint32_t stride = width * bytepp;
     for (int i = 0; i < height; i++) {
         rows[i] = buf + (stride * i);
     }
     rows[height] = nullptr;
+    png_set_strip_16(pngread);
     png_set_palette_to_rgb(pngread);
     png_read_image(pngread, (png_bytepp)&rows.front());
     png_destroy_read_struct(&pngread, &pnginfo, nullptr);
 }
 
-static const EGLint kEGLConfigAttribs[] = {
-    EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
-    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-    EGL_NONE
-};
-
-static bool
-CreateConfig(EGLConfig* aConfig, EGLDisplay display, int format)
-{
-    EGLConfig configs[64];
-    EGLint ncfg = ArrayLength(configs);
-
-    if (!eglChooseConfig(display, kEGLConfigAttribs,
-                         configs, ncfg, &ncfg) ||
-        ncfg < 1) {
-        return false;
-    }
-
-    for (int j = 0; j < ncfg; ++j) {
-        EGLConfig config = configs[j];
-        EGLint id;
-
-        if (eglGetConfigAttrib(display, config,
-                               EGL_NATIVE_VISUAL_ID, &id) &&
-            id > 0 && id == format)
-        {
-            *aConfig = config;
-            return true;
-        }
-    }
-    return false;
-}
-
 static void *
 AnimationThread(void *)
 {
     ZipReader reader;
     if (!reader.OpenArchive("/system/media/bootanimation.zip")) {
         LOGW("Could not open boot animation");
         return nullptr;
     }
 
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglInitialize(display, nullptr, nullptr);
-
-    int format;
-    ANativeWindow const * const window = gNativeWindow.get();
-    window->query(window, NATIVE_WINDOW_FORMAT, &format);
-
-    EGLConfig config;
-    if (!CreateConfig(&config, display, format)) {
-        LOGW("Could not find config for pixel format");
-        return nullptr;
-    }
-
-    EGLSurface surface = eglCreateWindowSurface(display, config, gNativeWindow.get(), nullptr);
-
     const cdir_entry *entry = nullptr;
     const local_file_header *file = nullptr;
     while ((entry = reader.GetNextEntry(entry))) {
         string name = reader.GetEntryName(entry);
         if (!name.compare("desc.txt")) {
             file = reader.GetLocalEntry(entry);
             break;
         }
     }
 
     if (!file) {
         LOGW("Could not find desc.txt in boot animation");
         return nullptr;
     }
 
+    int format;
+    ANativeWindow *window = gNativeWindow.get();
+    window->query(window, NATIVE_WINDOW_FORMAT, &format);
+
+    hw_module_t const *module;
+    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) {
+        LOGW("Could not get gralloc module");
+        return nullptr;
+    }
+    gralloc_module_t const *grmodule =
+        reinterpret_cast<gralloc_module_t const*>(module);
+
     string descCopy;
     descCopy.append(file->GetData(), entry->GetDataSize());
     int32_t width, height, fps;
     const char *line = descCopy.c_str();
     const char *end;
     bool headerRead = true;
     vector<AnimationPart> parts;
 
@@ -448,167 +448,77 @@ AnimationThread(void *)
             AnimationFrame &frame = part.frames.back();
             strcpy(frame.path, name.c_str());
             frame.file = reader.GetLocalEntry(entry);
         }
 
         sort(part.frames.begin(), part.frames.end());
     }
 
-    static EGLint gContextAttribs[] = {
-        EGL_CONTEXT_CLIENT_VERSION, 2,
-        EGL_NONE, 0
-    };
-    EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, gContextAttribs);
-
-    eglMakeCurrent(display, surface, surface, context);
-    glEnable(GL_TEXTURE_2D);
-
-    const char *vsString =
-        "attribute vec2 aPosition; "
-        "attribute vec2 aTexCoord; "
-        "varying vec2 vTexCoord; "
-        "void main() { "
-        "  gl_Position = vec4(aPosition, 0.0, 1.0); "
-        "  vTexCoord = aTexCoord; "
-        "}";
-
-    const char *fsString =
-        "precision mediump float; "
-        "varying vec2 vTexCoord; "
-        "uniform sampler2D sTexture; "
-        "void main() { "
-        "  gl_FragColor = vec4(texture2D(sTexture, vTexCoord).rgb, 1.0); "
-        "}";
-
-    GLint status;
-    GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
-    glShaderSource(vsh, 1, &vsString, nullptr);
-    glCompileShader(vsh);
-    glGetShaderiv(vsh, GL_COMPILE_STATUS, &status);
-    if (!status) {
-        LOGE("Failed to compile vertex shader");
-        return nullptr;
-    }
-
-    GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(fsh, 1, &fsString, nullptr);
-    glCompileShader(fsh);
-    glGetShaderiv(fsh, GL_COMPILE_STATUS, &status);
-    if (!status) {
-        LOGE("Failed to compile fragment shader");
-        return nullptr;
-    }
-
-    GLuint programId = glCreateProgram();
-    glAttachShader(programId, vsh);
-    glAttachShader(programId, fsh);
-
-    glLinkProgram(programId);
-    glGetProgramiv(programId, GL_LINK_STATUS, &status);
-    if (!status) {
-        LOG("Failed to link program");
-        return nullptr;
-    }
-
-    GLint positionLoc = glGetAttribLocation(programId, "aPosition");
-    GLint texCoordLoc = glGetAttribLocation(programId, "aTexCoord");
-    GLint textureLoc = glGetUniformLocation(programId, "sTexture");
-
-    glUseProgram(programId);
-
-    GLfloat texCoords[] = { 0.0f, 1.0f,
-                            0.0f, 0.0f,
-                            1.0f, 1.0f,
-                            1.0f, 0.0f };
-
-    GLfloat vCoords[] = { -1.0f, -1.0f,
-                          -1.0f,  1.0f,
-                           1.0f, -1.0f,
-                           1.0f,  1.0f };
-
-    GLuint rectBuf, texBuf;
-    glGenBuffers(1, &rectBuf);
-    glGenBuffers(1, &texBuf);
-
-    GLuint tex;
-    glGenTextures(1, &tex);
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, tex);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-    glEnableVertexAttribArray(positionLoc);
-    glBindBuffer(GL_ARRAY_BUFFER, rectBuf);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(vCoords), vCoords, GL_STATIC_DRAW);
-    glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-    glEnableVertexAttribArray(texCoordLoc);
-    glBindBuffer(GL_ARRAY_BUFFER, texBuf);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
-    glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-    glUniform1i(textureLoc, 0);
-
     uint32_t frameDelayUs = 1000000 / fps;
 
     for (uint32_t i = 0; i < parts.size(); i++) {
         AnimationPart &part = parts[i];
 
         uint32_t j = 0;
         while (sRunAnimation && (!part.count || j++ < part.count)) {
             for (uint32_t k = 0; k < part.frames.size(); k++) {
                 struct timeval tv1, tv2;
                 gettimeofday(&tv1, nullptr);
                 AnimationFrame &frame = part.frames[k];
                 if (!frame.buf) {
-                    frame.ReadPngFrame();
+                    frame.ReadPngFrame(format);
+                }
+
+                ANativeWindowBuffer *buf;
+                if (window->dequeueBuffer(window, &buf)) {
+                    LOGW("Failed to get an ANativeWindowBuffer");
+                    break;
+                }
+                if (window->lockBuffer(window, buf)) {
+                    LOGW("Failed to lock ANativeWindowBuffer");
+                    window->queueBuffer(window, buf);
+                    break;
                 }
 
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
-                             frame.width, frame.height, 0,
-                             GL_RGB, GL_UNSIGNED_BYTE, frame.buf);
-                glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+                void *vaddr;
+                if (grmodule->lock(grmodule, buf->handle,
+                                   GRALLOC_USAGE_SW_READ_NEVER |
+                                   GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                   GRALLOC_USAGE_HW_FB,
+                                   0, 0, width, height, &vaddr)) {
+                    LOGW("Failed to lock buffer_handle_t");
+                    window->queueBuffer(window, buf);
+                    break;
+                }
+                memcpy(vaddr, frame.buf,
+                       frame.width * frame.height * frame.bytepp);
+                grmodule->unlock(grmodule, buf->handle);
 
                 gettimeofday(&tv2, nullptr);
 
                 timersub(&tv2, &tv1, &tv2);
 
                 if (tv2.tv_usec < frameDelayUs) {
                     usleep(frameDelayUs - tv2.tv_usec);
                 } else {
                     LOGW("Frame delay is %d us but decoding took %d us", frameDelayUs, tv2.tv_usec);
                 }
 
-                eglSwapBuffers(display, surface);
+                window->queueBuffer(window, buf);
 
                 if (part.count && j >= part.count) {
                     free(frame.buf);
                     frame.buf = nullptr;
                 }
             }
             usleep(frameDelayUs * part.pause);
         }
     }
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glUseProgram(0);
-    glDeleteTextures(1, &tex);
-    glDeleteBuffers(1, &texBuf);
-    glDeleteBuffers(1, &rectBuf);
-    glDeleteProgram(programId);
-    glDeleteShader(fsh);
-    glDeleteShader(vsh);
 
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-    eglDestroyContext(display, context);
-    eglDestroySurface(display, surface);
     return nullptr;
 }
 
 static int
 CancelBufferNoop(ANativeWindow* aWindow, android_native_buffer_t* aBuffer)
 {
     return 0;
 }
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -22,18 +22,16 @@ else
 PROGRAM=$(MOZ_APP_NAME)$(BIN_SUFFIX)
 endif
 
 CPPSRCS = nsBrowserApp.cpp
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += BootAnimation.cpp
 LIBS += \
-  -lGLESv2 \
-  -lEGL \
   -lui \
   -lhardware_legacy \
   -lhardware \
   -lcutils \
   $(DEPTH)/media/libpng/$(LIB_PREFIX)mozpng.$(LIB_SUFFIX) \
   $(MOZ_ZLIB_LIBS) \
   $(NULL)
 OS_LDFLAGS += -Wl,--export-dynamic
--- a/media/libpng/mozpngconf.h
+++ b/media/libpng/mozpngconf.h
@@ -40,19 +40,24 @@
 #define PNG_READ_GRAY_TO_RGB_SUPPORTED
 #define PNG_READ_INTERLACING_SUPPORTED
 #define PNG_READ_SCALE_16_TO_8_SUPPORTED
 #define PNG_READ_TRANSFORMS_SUPPORTED
 #endif
 
 /* necessary for boot animation code */
 #ifdef MOZ_WIDGET_GONK
+#define PNG_EASY_ACCESS_SUPPORTED
+#define PNG_READ_BGR_SUPPORTED
+#define PNG_READ_EXPAND_SUPPORTED
+#define PNG_READ_FILLER_SUPPORTED
+#define PNG_READ_STRIP_16_TO_8_SUPPORTED
+#define PNG_READ_STRIP_ALPHA_SUPPORTED
+#define PNG_READ_USER_TRANSFORM_SUPPORTED
 #define PNG_SEQUENTIAL_READ_SUPPORTED
-#define PNG_EASY_ACCESS_SUPPORTED
-#define PNG_READ_EXPAND_SUPPORTED
 #endif
 
 #ifdef MOZ_PNG_WRITE
 #define PNG_WRITE_SUPPORTED
 #define PNG_WRITE_APNG_SUPPORTED
 #define PNG_WRITE_tRNS_SUPPORTED
 #define PNG_WRITE_16BIT_SUPPORTED
 #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED