Home | History | Annotate | Download | only in bootanimation
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "BootAnimation"
     18 
     19 #include <stdint.h>
     20 #include <sys/types.h>
     21 #include <math.h>
     22 #include <fcntl.h>
     23 #include <utils/misc.h>
     24 #include <signal.h>
     25 
     26 #include <binder/IPCThreadState.h>
     27 #include <utils/threads.h>
     28 #include <utils/Atomic.h>
     29 #include <utils/Errors.h>
     30 #include <utils/Log.h>
     31 #include <utils/AssetManager.h>
     32 
     33 #include <ui/PixelFormat.h>
     34 #include <ui/Rect.h>
     35 #include <ui/Region.h>
     36 #include <ui/DisplayInfo.h>
     37 #include <ui/FramebufferNativeWindow.h>
     38 #include <ui/EGLUtils.h>
     39 
     40 #include <surfaceflinger/ISurfaceComposer.h>
     41 #include <surfaceflinger/ISurfaceComposerClient.h>
     42 
     43 #include <core/SkBitmap.h>
     44 #include <images/SkImageDecoder.h>
     45 
     46 #include <GLES/gl.h>
     47 #include <GLES/glext.h>
     48 #include <EGL/eglext.h>
     49 
     50 #include "BootAnimation.h"
     51 
     52 namespace android {
     53 
     54 // ---------------------------------------------------------------------------
     55 
     56 BootAnimation::BootAnimation() : Thread(false)
     57 {
     58     mSession = new SurfaceComposerClient();
     59 }
     60 
     61 BootAnimation::~BootAnimation() {
     62 }
     63 
     64 void BootAnimation::onFirstRef() {
     65     status_t err = mSession->linkToComposerDeath(this);
     66     LOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
     67     if (err == NO_ERROR) {
     68         run("BootAnimation", PRIORITY_DISPLAY);
     69     }
     70 }
     71 
     72 sp<SurfaceComposerClient> BootAnimation::session() const {
     73     return mSession;
     74 }
     75 
     76 
     77 void BootAnimation::binderDied(const wp<IBinder>& who)
     78 {
     79     // woah, surfaceflinger died!
     80     LOGD("SurfaceFlinger died, exiting...");
     81 
     82     // calling requestExit() is not enough here because the Surface code
     83     // might be blocked on a condition variable that will never be updated.
     84     kill( getpid(), SIGKILL );
     85     requestExit();
     86 }
     87 
     88 status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
     89         const char* name) {
     90     Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
     91     if (!asset)
     92         return NO_INIT;
     93     SkBitmap bitmap;
     94     SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
     95             &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
     96     asset->close();
     97     delete asset;
     98 
     99     // ensure we can call getPixels(). No need to call unlock, since the
    100     // bitmap will go out of scope when we return from this method.
    101     bitmap.lockPixels();
    102 
    103     const int w = bitmap.width();
    104     const int h = bitmap.height();
    105     const void* p = bitmap.getPixels();
    106 
    107     GLint crop[4] = { 0, h, w, -h };
    108     texture->w = w;
    109     texture->h = h;
    110 
    111     glGenTextures(1, &texture->name);
    112     glBindTexture(GL_TEXTURE_2D, texture->name);
    113 
    114     switch (bitmap.getConfig()) {
    115         case SkBitmap::kA8_Config:
    116             glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
    117                     GL_UNSIGNED_BYTE, p);
    118             break;
    119         case SkBitmap::kARGB_4444_Config:
    120             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
    121                     GL_UNSIGNED_SHORT_4_4_4_4, p);
    122             break;
    123         case SkBitmap::kARGB_8888_Config:
    124             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
    125                     GL_UNSIGNED_BYTE, p);
    126             break;
    127         case SkBitmap::kRGB_565_Config:
    128             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
    129                     GL_UNSIGNED_SHORT_5_6_5, p);
    130             break;
    131         default:
    132             break;
    133     }
    134 
    135     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
    136     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    137     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    138     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    139     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    140     return NO_ERROR;
    141 }
    142 
    143 status_t BootAnimation::initTexture(void* buffer, size_t len)
    144 {
    145     //StopWatch watch("blah");
    146 
    147     SkBitmap bitmap;
    148     SkImageDecoder::DecodeMemory(buffer, len,
    149             &bitmap, SkBitmap::kRGB_565_Config,
    150             SkImageDecoder::kDecodePixels_Mode);
    151 
    152     // ensure we can call getPixels(). No need to call unlock, since the
    153     // bitmap will go out of scope when we return from this method.
    154     bitmap.lockPixels();
    155 
    156     const int w = bitmap.width();
    157     const int h = bitmap.height();
    158     const void* p = bitmap.getPixels();
    159 
    160     GLint crop[4] = { 0, h, w, -h };
    161     int tw = 1 << (31 - __builtin_clz(w));
    162     int th = 1 << (31 - __builtin_clz(h));
    163     if (tw < w) tw <<= 1;
    164     if (th < h) th <<= 1;
    165 
    166     switch (bitmap.getConfig()) {
    167         case SkBitmap::kARGB_8888_Config:
    168             if (tw != w || th != h) {
    169                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
    170                         GL_UNSIGNED_BYTE, 0);
    171                 glTexSubImage2D(GL_TEXTURE_2D, 0,
    172                         0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
    173             } else {
    174                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
    175                         GL_UNSIGNED_BYTE, p);
    176             }
    177             break;
    178 
    179         case SkBitmap::kRGB_565_Config:
    180             if (tw != w || th != h) {
    181                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
    182                         GL_UNSIGNED_SHORT_5_6_5, 0);
    183                 glTexSubImage2D(GL_TEXTURE_2D, 0,
    184                         0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
    185             } else {
    186                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
    187                         GL_UNSIGNED_SHORT_5_6_5, p);
    188             }
    189             break;
    190         default:
    191             break;
    192     }
    193 
    194     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
    195 
    196     return NO_ERROR;
    197 }
    198 
    199 status_t BootAnimation::readyToRun() {
    200     mAssets.addDefaultAssets();
    201 
    202     DisplayInfo dinfo;
    203     status_t status = session()->getDisplayInfo(0, &dinfo);
    204     if (status)
    205         return -1;
    206 
    207     // create the native surface
    208     sp<SurfaceControl> control = session()->createSurface(
    209             getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
    210     session()->openTransaction();
    211     control->setLayer(0x40000000);
    212     session()->closeTransaction();
    213 
    214     sp<Surface> s = control->getSurface();
    215 
    216     // initialize opengl and egl
    217     const EGLint attribs[] = {
    218             EGL_DEPTH_SIZE, 0,
    219             EGL_NONE
    220     };
    221     EGLint w, h, dummy;
    222     EGLint numConfigs;
    223     EGLConfig config;
    224     EGLSurface surface;
    225     EGLContext context;
    226 
    227     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    228 
    229     eglInitialize(display, 0, 0);
    230     EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config);
    231     surface = eglCreateWindowSurface(display, config, s.get(), NULL);
    232     context = eglCreateContext(display, config, NULL, NULL);
    233     eglQuerySurface(display, surface, EGL_WIDTH, &w);
    234     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
    235 
    236     if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
    237         return NO_INIT;
    238 
    239     mDisplay = display;
    240     mContext = context;
    241     mSurface = surface;
    242     mWidth = w;
    243     mHeight = h;
    244     mFlingerSurfaceControl = control;
    245     mFlingerSurface = s;
    246 
    247     mAndroidAnimation = false;
    248     status_t err = mZip.open("/data/local/bootanimation.zip");
    249     if (err != NO_ERROR) {
    250         err = mZip.open("/system/media/bootanimation.zip");
    251         if (err != NO_ERROR) {
    252             mAndroidAnimation = true;
    253         }
    254     }
    255 
    256     return NO_ERROR;
    257 }
    258 
    259 bool BootAnimation::threadLoop()
    260 {
    261     bool r;
    262     if (mAndroidAnimation) {
    263         r = android();
    264     } else {
    265         r = movie();
    266     }
    267 
    268     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    269     eglDestroyContext(mDisplay, mContext);
    270     eglDestroySurface(mDisplay, mSurface);
    271     mFlingerSurface.clear();
    272     mFlingerSurfaceControl.clear();
    273     eglTerminate(mDisplay);
    274     IPCThreadState::self()->stopProcess();
    275     return r;
    276 }
    277 
    278 bool BootAnimation::android()
    279 {
    280     initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
    281     initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
    282 
    283     // clear screen
    284     glShadeModel(GL_FLAT);
    285     glDisable(GL_DITHER);
    286     glDisable(GL_SCISSOR_TEST);
    287     glClear(GL_COLOR_BUFFER_BIT);
    288     eglSwapBuffers(mDisplay, mSurface);
    289 
    290     glEnable(GL_TEXTURE_2D);
    291     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    292 
    293     const GLint xc = (mWidth  - mAndroid[0].w) / 2;
    294     const GLint yc = (mHeight - mAndroid[0].h) / 2;
    295     const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
    296 
    297     // draw and update only what we need
    298     mFlingerSurface->setSwapRectangle(updateRect);
    299 
    300     glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
    301             updateRect.height());
    302 
    303     // Blend state
    304     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    305     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    306 
    307     const nsecs_t startTime = systemTime();
    308     do {
    309         nsecs_t now = systemTime();
    310         double time = now - startTime;
    311         float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
    312         GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
    313         GLint x = xc - offset;
    314 
    315         glDisable(GL_SCISSOR_TEST);
    316         glClear(GL_COLOR_BUFFER_BIT);
    317 
    318         glEnable(GL_SCISSOR_TEST);
    319         glDisable(GL_BLEND);
    320         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
    321         glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
    322         glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
    323 
    324         glEnable(GL_BLEND);
    325         glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
    326         glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
    327 
    328         EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
    329         if (res == EGL_FALSE)
    330             break;
    331 
    332         // 12fps: don't animate too fast to preserve CPU
    333         const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
    334         if (sleepTime > 0)
    335             usleep(sleepTime);
    336     } while (!exitPending());
    337 
    338     glDeleteTextures(1, &mAndroid[0].name);
    339     glDeleteTextures(1, &mAndroid[1].name);
    340     return false;
    341 }
    342 
    343 
    344 bool BootAnimation::movie()
    345 {
    346     ZipFileRO& zip(mZip);
    347 
    348     size_t numEntries = zip.getNumEntries();
    349     ZipEntryRO desc = zip.findEntryByName("desc.txt");
    350     FileMap* descMap = zip.createEntryFileMap(desc);
    351     LOGE_IF(!descMap, "descMap is null");
    352     if (!descMap) {
    353         return false;
    354     }
    355 
    356     String8 desString((char const*)descMap->getDataPtr(),
    357             descMap->getDataLength());
    358     char const* s = desString.string();
    359 
    360     Animation animation;
    361 
    362     // Parse the description file
    363     for (;;) {
    364         const char* endl = strstr(s, "\n");
    365         if (!endl) break;
    366         String8 line(s, endl - s);
    367         const char* l = line.string();
    368         int fps, width, height, count, pause;
    369         char path[256];
    370         if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
    371             //LOGD("> w=%d, h=%d, fps=%d", fps, width, height);
    372             animation.width = width;
    373             animation.height = height;
    374             animation.fps = fps;
    375         }
    376         if (sscanf(l, "p %d %d %s", &count, &pause, path) == 3) {
    377             //LOGD("> count=%d, pause=%d, path=%s", count, pause, path);
    378             Animation::Part part;
    379             part.count = count;
    380             part.pause = pause;
    381             part.path = path;
    382             animation.parts.add(part);
    383         }
    384         s = ++endl;
    385     }
    386 
    387     // read all the data structures
    388     const size_t pcount = animation.parts.size();
    389     for (size_t i=0 ; i<numEntries ; i++) {
    390         char name[256];
    391         ZipEntryRO entry = zip.findEntryByIndex(i);
    392         if (zip.getEntryFileName(entry, name, 256) == 0) {
    393             const String8 entryName(name);
    394             const String8 path(entryName.getPathDir());
    395             const String8 leaf(entryName.getPathLeaf());
    396             if (leaf.size() > 0) {
    397                 for (int j=0 ; j<pcount ; j++) {
    398                     if (path == animation.parts[j].path) {
    399                         int method;
    400                         // supports only stored png files
    401                         if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {
    402                             if (method == ZipFileRO::kCompressStored) {
    403                                 FileMap* map = zip.createEntryFileMap(entry);
    404                                 if (map) {
    405                                     Animation::Frame frame;
    406                                     frame.name = leaf;
    407                                     frame.map = map;
    408                                     Animation::Part& part(animation.parts.editItemAt(j));
    409                                     part.frames.add(frame);
    410                                 }
    411                             }
    412                         }
    413                     }
    414                 }
    415             }
    416         }
    417     }
    418 
    419     // clear screen
    420     glShadeModel(GL_FLAT);
    421     glDisable(GL_DITHER);
    422     glDisable(GL_SCISSOR_TEST);
    423     glDisable(GL_BLEND);
    424     glClear(GL_COLOR_BUFFER_BIT);
    425 
    426     eglSwapBuffers(mDisplay, mSurface);
    427 
    428     glBindTexture(GL_TEXTURE_2D, 0);
    429     glEnable(GL_TEXTURE_2D);
    430     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    431     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    432     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    433     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    434     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    435 
    436     const int xc = (mWidth - animation.width) / 2;
    437     const int yc = ((mHeight - animation.height) / 2);
    438     nsecs_t lastFrame = systemTime();
    439     nsecs_t frameDuration = s2ns(1) / animation.fps;
    440 
    441     Region clearReg(Rect(mWidth, mHeight));
    442     clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
    443 
    444     for (int i=0 ; i<pcount && !exitPending() ; i++) {
    445         const Animation::Part& part(animation.parts[i]);
    446         const size_t fcount = part.frames.size();
    447         glBindTexture(GL_TEXTURE_2D, 0);
    448 
    449         for (int r=0 ; !part.count || r<part.count ; r++) {
    450             for (int j=0 ; j<fcount && !exitPending(); j++) {
    451                 const Animation::Frame& frame(part.frames[j]);
    452 
    453                 if (r > 0) {
    454                     glBindTexture(GL_TEXTURE_2D, frame.tid);
    455                 } else {
    456                     if (part.count != 1) {
    457                         glGenTextures(1, &frame.tid);
    458                         glBindTexture(GL_TEXTURE_2D, frame.tid);
    459                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    460                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    461                     }
    462                     initTexture(
    463                             frame.map->getDataPtr(),
    464                             frame.map->getDataLength());
    465                 }
    466 
    467                 if (!clearReg.isEmpty()) {
    468                     Region::const_iterator head(clearReg.begin());
    469                     Region::const_iterator tail(clearReg.end());
    470                     glEnable(GL_SCISSOR_TEST);
    471                     while (head != tail) {
    472                         const Rect& r(*head++);
    473                         glScissor(r.left, mHeight - r.bottom,
    474                                 r.width(), r.height());
    475                         glClear(GL_COLOR_BUFFER_BIT);
    476                     }
    477                     glDisable(GL_SCISSOR_TEST);
    478                 }
    479                 glDrawTexiOES(xc, yc, 0, animation.width, animation.height);
    480                 eglSwapBuffers(mDisplay, mSurface);
    481 
    482                 nsecs_t now = systemTime();
    483                 nsecs_t delay = frameDuration - (now - lastFrame);
    484                 lastFrame = now;
    485                 long wait = ns2us(frameDuration);
    486                 if (wait > 0)
    487                     usleep(wait);
    488             }
    489             usleep(part.pause * ns2us(frameDuration));
    490         }
    491 
    492         // free the textures for this part
    493         if (part.count != 1) {
    494             for (int j=0 ; j<fcount ; j++) {
    495                 const Animation::Frame& frame(part.frames[j]);
    496                 glDeleteTextures(1, &frame.tid);
    497             }
    498         }
    499     }
    500 
    501     return false;
    502 }
    503 
    504 // ---------------------------------------------------------------------------
    505 
    506 }
    507 ; // namespace android
    508