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