diff options
Diffstat (limited to 'cmds/bootanimation/BootAnimation.cpp')
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp new file mode 100644 index 0000000..e2d01de --- /dev/null +++ b/cmds/bootanimation/BootAnimation.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 <stdint.h> +#include <sys/types.h> +#include <math.h> +#include <fcntl.h> +#include <utils/misc.h> + +#include <binder/IPCThreadState.h> +#include <utils/threads.h> +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/AssetManager.h> + +#include <ui/PixelFormat.h> +#include <ui/Rect.h> +#include <ui/Region.h> +#include <ui/DisplayInfo.h> +#include <ui/ISurfaceComposer.h> +#include <ui/ISurfaceFlingerClient.h> +#include <ui/FramebufferNativeWindow.h> + +#include <core/SkBitmap.h> +#include <images/SkImageDecoder.h> + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <EGL/eglext.h> + +#include "BootAnimation.h" + +namespace android { + +// --------------------------------------------------------------------------- + +BootAnimation::BootAnimation() : Thread(false) +{ + mSession = new SurfaceComposerClient(); +} + +BootAnimation::~BootAnimation() { +} + +void BootAnimation::onFirstRef() { + run("BootAnimation", PRIORITY_DISPLAY); +} + +const sp<SurfaceComposerClient>& BootAnimation::session() const { + return mSession; +} + +status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, + const char* name) { + Asset* asset = assets.open(name, Asset::ACCESS_BUFFER); + if (!asset) + return NO_INIT; + SkBitmap bitmap; + SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), + &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode); + asset->close(); + delete asset; + + // ensure we can call getPixels(). No need to call unlock, since the + // bitmap will go out of scope when we return from this method. + bitmap.lockPixels(); + + const int w = bitmap.width(); + const int h = bitmap.height(); + const void* p = bitmap.getPixels(); + + GLint crop[4] = { 0, h, w, -h }; + texture->w = w; + texture->h = h; + + glGenTextures(1, &texture->name); + glBindTexture(GL_TEXTURE_2D, texture->name); + + switch (bitmap.getConfig()) { + case SkBitmap::kA8_Config: + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, + GL_UNSIGNED_BYTE, p); + break; + case SkBitmap::kARGB_4444_Config: + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, + GL_UNSIGNED_SHORT_4_4_4_4, p); + break; + case SkBitmap::kARGB_8888_Config: + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, + GL_UNSIGNED_BYTE, p); + break; + case SkBitmap::kRGB_565_Config: + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, p); + break; + default: + break; + } + + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + return NO_ERROR; +} + +status_t BootAnimation::readyToRun() { + mAssets.addDefaultAssets(); + + DisplayInfo dinfo; + status_t status = session()->getDisplayInfo(0, &dinfo); + if (status) + return -1; + + // create the native surface + sp<SurfaceControl> control = session()->createSurface( + getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565, + ISurfaceComposer::eGPU); + session()->openTransaction(); + control->setLayer(0x40000000); + session()->closeTransaction(); + + sp<Surface> s = control->getSurface(); + + // initialize opengl and egl + const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE }; + EGLint w, h, dummy; + EGLint numConfigs; + EGLConfig config; + EGLSurface surface; + EGLContext context; + + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + + eglInitialize(display, 0, 0); + eglChooseConfig(display, attribs, &config, 1, &numConfigs); + + surface = eglCreateWindowSurface(display, config, s.get(), NULL); + + context = eglCreateContext(display, config, NULL, NULL); + eglQuerySurface(display, surface, EGL_WIDTH, &w); + eglQuerySurface(display, surface, EGL_HEIGHT, &h); + eglMakeCurrent(display, surface, surface, context); + mDisplay = display; + mContext = context; + mSurface = surface; + mWidth = w; + mHeight = h; + mFlingerSurfaceControl = control; + mFlingerSurface = s; + + // initialize GL + glShadeModel(GL_FLAT); + glEnable(GL_TEXTURE_2D); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + return NO_ERROR; +} + +bool BootAnimation::threadLoop() { + bool r = android(); + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(mDisplay, mContext); + eglDestroySurface(mDisplay, mSurface); + mFlingerSurface.clear(); + mFlingerSurfaceControl.clear(); + eglTerminate(mDisplay); + IPCThreadState::self()->stopProcess(); + return r; +} + +bool BootAnimation::android() { + initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png"); + initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png"); + + // clear screen + glDisable(GL_DITHER); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT); + eglSwapBuffers(mDisplay, mSurface); + + const GLint xc = (mWidth - mAndroid[0].w) / 2; + const GLint yc = (mHeight - mAndroid[0].h) / 2; + const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h); + + // draw and update only what we need + mFlingerSurface->setSwapRectangle(updateRect); + + glEnable(GL_SCISSOR_TEST); + glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(), + updateRect.height()); + + // Blend state + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + const nsecs_t startTime = systemTime(); + do { + nsecs_t now = systemTime(); + double time = now - startTime; + float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w; + GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w; + GLint x = xc - offset; + + glDisable(GL_BLEND); + glBindTexture(GL_TEXTURE_2D, mAndroid[1].name); + glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h); + glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h); + + glEnable(GL_BLEND); + glBindTexture(GL_TEXTURE_2D, mAndroid[0].name); + glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h); + + EGLBoolean res = eglSwapBuffers(mDisplay, mSurface); + if (res == EGL_FALSE) + break; + + // 12fps: don't animate too fast to preserve CPU + const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now); + if (sleepTime > 0) + usleep(sleepTime); + } while (!exitPending()); + + glDeleteTextures(1, &mAndroid[0].name); + glDeleteTextures(1, &mAndroid[1].name); + return false; +} + +// --------------------------------------------------------------------------- + +} +; // namespace android |