BootAnimation.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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 25#include <utils/threads.h> 26#include <utils/Atomic.h> 27#include <utils/Errors.h> 28#include <utils/Log.h> 29#include <utils/AssetManager.h> 30 31#include <ui/PixelFormat.h> 32#include <ui/Rect.h> 33#include <ui/Region.h> 34#include <ui/DisplayInfo.h> 35#include <ui/ISurfaceComposer.h> 36#include <ui/ISurfaceFlingerClient.h> 37#include <ui/EGLNativeWindowSurface.h> 38 39#include <core/SkBitmap.h> 40#include <images/SkImageDecoder.h> 41 42#include <GLES/gl.h> 43#include <GLES/glext.h> 44#include <EGL/eglext.h> 45 46#include "BootAnimation.h" 47 48namespace android { 49 50// --------------------------------------------------------------------------- 51 52BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) : 53 Thread(false) { 54 mSession = SurfaceComposerClient::clientForConnection( 55 composer->createConnection()->asBinder()); 56} 57 58BootAnimation::~BootAnimation() { 59} 60 61void BootAnimation::onFirstRef() { 62 run("BootAnimation", PRIORITY_DISPLAY); 63} 64 65const sp<SurfaceComposerClient>& BootAnimation::session() const { 66 return mSession; 67} 68 69status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, 70 const char* name) { 71 Asset* asset = assets.open(name, Asset::ACCESS_BUFFER); 72 if (!asset) 73 return NO_INIT; 74 SkBitmap bitmap; 75 SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), 76 &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode); 77 asset->close(); 78 delete asset; 79 80 // ensure we can call getPixels(). No need to call unlock, since the 81 // bitmap will go out of scope when we return from this method. 82 bitmap.lockPixels(); 83 84 const int w = bitmap.width(); 85 const int h = bitmap.height(); 86 const void* p = bitmap.getPixels(); 87 88 GLint crop[4] = { 0, h, w, -h }; 89 texture->w = w; 90 texture->h = h; 91 92 glGenTextures(1, &texture->name); 93 glBindTexture(GL_TEXTURE_2D, texture->name); 94 95 switch (bitmap.getConfig()) { 96 case SkBitmap::kA8_Config: 97 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, 98 GL_UNSIGNED_BYTE, p); 99 break; 100 case SkBitmap::kARGB_4444_Config: 101 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, 102 GL_UNSIGNED_SHORT_4_4_4_4, p); 103 break; 104 case SkBitmap::kARGB_8888_Config: 105 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, 106 GL_UNSIGNED_BYTE, p); 107 break; 108 case SkBitmap::kRGB_565_Config: 109 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, 110 GL_UNSIGNED_SHORT_5_6_5, p); 111 break; 112 default: 113 break; 114 } 115 116 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); 117 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 118 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 119 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 120 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 121 return NO_ERROR; 122} 123 124status_t BootAnimation::readyToRun() { 125 mAssets.addDefaultAssets(); 126 127 DisplayInfo dinfo; 128 status_t status = session()->getDisplayInfo(0, &dinfo); 129 if (status) 130 return -1; 131 132 // create the native surface 133 sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h, 134 PIXEL_FORMAT_RGB_565); 135 session()->openTransaction(); 136 s->setLayer(0x40000000); 137 session()->closeTransaction(); 138 139 // initialize opengl and egl 140 const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, 141 EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE }; 142 EGLint w, h, dummy; 143 EGLint numConfigs; 144 EGLConfig config; 145 EGLSurface surface; 146 EGLContext context; 147 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 148 eglChooseConfig(display, attribs, &config, 1, &numConfigs); 149 150 mNativeWindowSurface = new EGLNativeWindowSurface(s); 151 surface = eglCreateWindowSurface(display, config, 152 mNativeWindowSurface.get(), NULL); 153 154 context = eglCreateContext(display, config, NULL, NULL); 155 eglQuerySurface(display, surface, EGL_WIDTH, &w); 156 eglQuerySurface(display, surface, EGL_HEIGHT, &h); 157 eglMakeCurrent(display, surface, surface, context); 158 mDisplay = display; 159 mContext = context; 160 mSurface = surface; 161 mWidth = w; 162 mHeight = h; 163 mFlingerSurface = s; 164 165 // initialize GL 166 glShadeModel(GL_FLAT); 167 glEnable(GL_DITHER); 168 glEnable(GL_TEXTURE_2D); 169 glEnable(GL_SCISSOR_TEST); 170 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 171 172 return NO_ERROR; 173} 174 175void BootAnimation::requestExit() { 176 mBarrier.open(); 177 Thread::requestExit(); 178} 179 180bool BootAnimation::threadLoop() { 181 bool r = android(); 182 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 183 eglDestroyContext(mDisplay, mContext); 184 eglDestroySurface(mDisplay, mSurface); 185 mNativeWindowSurface.clear(); 186 return r; 187} 188 189bool BootAnimation::android() { 190 initTexture(&mAndroid[0], mAssets, "images/android_320x480.png"); 191 initTexture(&mAndroid[1], mAssets, "images/boot_robot.png"); 192 initTexture(&mAndroid[2], mAssets, "images/boot_robot_glow.png"); 193 194 // erase screen 195 glDisable(GL_SCISSOR_TEST); 196 glBindTexture(GL_TEXTURE_2D, mAndroid[0].name); 197 198 // clear screen 199 glClear(GL_COLOR_BUFFER_BIT); 200 eglSwapBuffers(mDisplay, mSurface); 201 202 // wait ~1s 203 usleep(800000); 204 205 // fade in 206 glEnable(GL_BLEND); 207 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 208 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 209 const int steps = 8; 210 for (int i = 1; i < steps; i++) { 211 float fade = i / float(steps); 212 glColor4f(1, 1, 1, fade * fade); 213 glClear(GL_COLOR_BUFFER_BIT); 214 glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h); 215 eglSwapBuffers(mDisplay, mSurface); 216 } 217 218 // draw last frame 219 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 220 glDisable(GL_BLEND); 221 glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h); 222 eglSwapBuffers(mDisplay, mSurface); 223 224 // update rect for the robot 225 const int x = mWidth - mAndroid[1].w - 33; 226 const int y = (mHeight - mAndroid[1].h) / 2 - 1; 227 const Rect updateRect(x, y, x + mAndroid[1].w, y + mAndroid[1].h); 228 229 // draw and update only what we need 230 mNativeWindowSurface->setSwapRectangle(updateRect.left, 231 updateRect.top, updateRect.width(), updateRect.height()); 232 233 glEnable(GL_SCISSOR_TEST); 234 glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(), 235 updateRect.height()); 236 237 const nsecs_t startTime = systemTime(); 238 do { 239 // glow speed and shape 240 nsecs_t time = systemTime() - startTime; 241 float t = ((4.0f / (360.0f * us2ns(16667))) * time); 242 t = t - floorf(t); 243 const float fade = 0.5f + 0.5f * sinf(t * 2 * M_PI); 244 245 // fade the glow in and out 246 glDisable(GL_BLEND); 247 glBindTexture(GL_TEXTURE_2D, mAndroid[2].name); 248 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 249 glColor4f(fade, fade, fade, fade); 250 glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0, 251 updateRect.width(), updateRect.height()); 252 253 // draw the robot 254 glEnable(GL_BLEND); 255 glBindTexture(GL_TEXTURE_2D, mAndroid[1].name); 256 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 257 glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0, 258 updateRect.width(), updateRect.height()); 259 260 // make sure sleep a lot to not take too much CPU away from 261 // the boot process. With this "glow" animation there is no 262 // visible difference. 263 usleep(16667 * 4); 264 265 eglSwapBuffers(mDisplay, mSurface); 266 } while (!exitPending()); 267 268 glDeleteTextures(1, &mAndroid[0].name); 269 glDeleteTextures(1, &mAndroid[1].name); 270 glDeleteTextures(1, &mAndroid[2].name); 271 return false; 272} 273 274bool BootAnimation::cylon() { 275 // initialize the textures... 276 initTexture(&mLeftTrail, mAssets, "images/cylon_left.png"); 277 initTexture(&mRightTrail, mAssets, "images/cylon_right.png"); 278 initTexture(&mBrightSpot, mAssets, "images/cylon_dot.png"); 279 280 int w = mWidth; 281 int h = mHeight; 282 283 const Point c(w / 2, h / 2); 284 const GLint amplitude = 60; 285 const int scx = c.x - amplitude - mBrightSpot.w / 2; 286 const int scy = c.y - mBrightSpot.h / 2; 287 const int scw = amplitude * 2 + mBrightSpot.w; 288 const int sch = mBrightSpot.h; 289 const Rect updateRect(scx, h - scy - sch, scx + scw, h - scy); 290 291 // erase screen 292 glDisable(GL_SCISSOR_TEST); 293 glClear(GL_COLOR_BUFFER_BIT); 294 295 eglSwapBuffers(mDisplay, mSurface); 296 297 glClear(GL_COLOR_BUFFER_BIT); 298 299 mNativeWindowSurface->setSwapRectangle(updateRect.left, 300 updateRect.top, updateRect.width(), updateRect.height()); 301 302 glEnable(GL_SCISSOR_TEST); 303 glEnable(GL_BLEND); 304 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 305 306 // clear the screen to white 307 Point p; 308 float t = 0; 309 float alpha = 1.0f; 310 const nsecs_t startTime = systemTime(); 311 nsecs_t fadeTime = 0; 312 313 do { 314 // Set scissor in interesting area 315 glScissor(scx, scy, scw, sch); 316 317 // erase screen 318 glClear(GL_COLOR_BUFFER_BIT); 319 320 // compute wave 321 const float a = (t * 2 * M_PI) - M_PI / 2; 322 const float sn = sinf(a); 323 const float cs = cosf(a); 324 GLint x = GLint(amplitude * sn); 325 float derivative = cs; 326 327 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 328 329 if (derivative > 0) { 330 // vanishing trail... 331 p.x = (-amplitude + c.x) - mBrightSpot.w / 2; 332 p.y = c.y - mLeftTrail.h / 2; 333 float fade = 2.0f * (0.5f - t); 334 //fade *= fade; 335 glColor4f(fade, fade, fade, fade); 336 glBindTexture(GL_TEXTURE_2D, mLeftTrail.name); 337 glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h); 338 339 // trail... 340 p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16; 341 p.y = c.y - mRightTrail.h / 2; 342 fade = t < 0.25f ? t * 4.0f : 1.0f; 343 fade *= fade; 344 glColor4f(fade, fade, fade, fade); 345 glBindTexture(GL_TEXTURE_2D, mRightTrail.name); 346 glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h); 347 } else { 348 // vanishing trail.. 349 p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16; 350 p.y = c.y - mRightTrail.h / 2; 351 float fade = 2.0f * (0.5f - (t - 0.5f)); 352 //fade *= fade; 353 glColor4f(fade, fade, fade, fade); 354 glBindTexture(GL_TEXTURE_2D, mRightTrail.name); 355 glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h); 356 357 // trail... 358 p.x = (x + c.x) - mBrightSpot.w / 2; 359 p.y = c.y - mLeftTrail.h / 2; 360 fade = t < 0.5f + 0.25f ? (t - 0.5f) * 4.0f : 1.0f; 361 fade *= fade; 362 glColor4f(fade, fade, fade, fade); 363 glBindTexture(GL_TEXTURE_2D, mLeftTrail.name); 364 glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h); 365 } 366 367 const Point p(x + c.x - mBrightSpot.w / 2, c.y - mBrightSpot.h / 2); 368 glBindTexture(GL_TEXTURE_2D, mBrightSpot.name); 369 glColor4f(1, 0.5, 0.5, 1); 370 glDrawTexiOES(p.x, p.y, 0, mBrightSpot.w, mBrightSpot.h); 371 372 // update animation 373 nsecs_t time = systemTime() - startTime; 374 t = ((4.0f / (360.0f * us2ns(16667))) * time); 375 t = t - floorf(t); 376 377 eglSwapBuffers(mDisplay, mSurface); 378 379 if (exitPending()) { 380 if (fadeTime == 0) { 381 fadeTime = time; 382 } 383 time -= fadeTime; 384 alpha = 1.0f - ((float(time) * 6.0f) / float(s2ns(1))); 385 386 session()->openTransaction(); 387 mFlingerSurface->setAlpha(alpha * alpha); 388 session()->closeTransaction(); 389 } 390 } while (alpha > 0); 391 392 // cleanup 393 glFinish(); 394 glDeleteTextures(1, &mLeftTrail.name); 395 glDeleteTextures(1, &mRightTrail.name); 396 glDeleteTextures(1, &mBrightSpot.name); 397 return false; 398} 399 400// --------------------------------------------------------------------------- 401 402} 403; // namespace android 404