Home | History | Annotate | Download | only in DisplayHardware
      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 #include <stdlib.h>
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include <math.h>
     21 
     22 #include <cutils/properties.h>
     23 
     24 #include <utils/RefBase.h>
     25 #include <utils/Log.h>
     26 
     27 #include <ui/PixelFormat.h>
     28 #include <ui/FramebufferNativeWindow.h>
     29 
     30 #include <GLES/gl.h>
     31 #include <EGL/egl.h>
     32 #include <EGL/eglext.h>
     33 
     34 #include "DisplayHardware/DisplayHardware.h"
     35 
     36 #include <hardware/gralloc.h>
     37 
     38 #include "DisplayHardwareBase.h"
     39 #include "GLExtensions.h"
     40 #include "HWComposer.h"
     41 #include "SurfaceFlinger.h"
     42 
     43 using namespace android;
     44 
     45 
     46 static __attribute__((noinline))
     47 void checkGLErrors()
     48 {
     49     do {
     50         // there could be more than one error flag
     51         GLenum error = glGetError();
     52         if (error == GL_NO_ERROR)
     53             break;
     54         ALOGE("GL error 0x%04x", int(error));
     55     } while(true);
     56 }
     57 
     58 static __attribute__((noinline))
     59 void checkEGLErrors(const char* token)
     60 {
     61     struct EGLUtils {
     62         static const char *strerror(EGLint err) {
     63             switch (err){
     64                 case EGL_SUCCESS:           return "EGL_SUCCESS";
     65                 case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
     66                 case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
     67                 case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
     68                 case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
     69                 case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
     70                 case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
     71                 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
     72                 case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
     73                 case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
     74                 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
     75                 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
     76                 case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
     77                 case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
     78                 case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
     79                 default: return "UNKNOWN";
     80             }
     81         }
     82     };
     83 
     84     EGLint error = eglGetError();
     85     if (error && error != EGL_SUCCESS) {
     86         ALOGE("%s: EGL error 0x%04x (%s)",
     87                 token, int(error), EGLUtils::strerror(error));
     88     }
     89 }
     90 
     91 /*
     92  * Initialize the display to the specified values.
     93  *
     94  */
     95 
     96 DisplayHardware::DisplayHardware(
     97         const sp<SurfaceFlinger>& flinger,
     98         uint32_t dpy)
     99     : DisplayHardwareBase(flinger, dpy),
    100       mFlinger(flinger), mFlags(0), mHwc(0)
    101 {
    102     init(dpy);
    103 }
    104 
    105 DisplayHardware::~DisplayHardware()
    106 {
    107     fini();
    108 }
    109 
    110 float DisplayHardware::getDpiX() const          { return mDpiX; }
    111 float DisplayHardware::getDpiY() const          { return mDpiY; }
    112 float DisplayHardware::getDensity() const       { return mDensity; }
    113 float DisplayHardware::getRefreshRate() const   { return mRefreshRate; }
    114 int DisplayHardware::getWidth() const           { return mWidth; }
    115 int DisplayHardware::getHeight() const          { return mHeight; }
    116 PixelFormat DisplayHardware::getFormat() const  { return mFormat; }
    117 uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
    118 
    119 uint32_t DisplayHardware::getMaxViewportDims() const {
    120     return mMaxViewportDims[0] < mMaxViewportDims[1] ?
    121             mMaxViewportDims[0] : mMaxViewportDims[1];
    122 }
    123 
    124 static status_t selectConfigForPixelFormat(
    125         EGLDisplay dpy,
    126         EGLint const* attrs,
    127         PixelFormat format,
    128         EGLConfig* outConfig)
    129 {
    130     EGLConfig config = NULL;
    131     EGLint numConfigs = -1, n=0;
    132     eglGetConfigs(dpy, NULL, 0, &numConfigs);
    133     EGLConfig* const configs = new EGLConfig[numConfigs];
    134     eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
    135     for (int i=0 ; i<n ; i++) {
    136         EGLint nativeVisualId = 0;
    137         eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
    138         if (nativeVisualId>0 && format == nativeVisualId) {
    139             *outConfig = configs[i];
    140             delete [] configs;
    141             return NO_ERROR;
    142         }
    143     }
    144     delete [] configs;
    145     return NAME_NOT_FOUND;
    146 }
    147 
    148 
    149 void DisplayHardware::init(uint32_t dpy)
    150 {
    151     mNativeWindow = new FramebufferNativeWindow();
    152     framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
    153     if (!fbDev) {
    154         ALOGE("Display subsystem failed to initialize. check logs. exiting...");
    155         exit(0);
    156     }
    157 
    158     int format;
    159     ANativeWindow const * const window = mNativeWindow.get();
    160     window->query(window, NATIVE_WINDOW_FORMAT, &format);
    161     mDpiX = mNativeWindow->xdpi;
    162     mDpiY = mNativeWindow->ydpi;
    163     mRefreshRate = fbDev->fps;
    164 
    165     if (mDpiX == 0 || mDpiY == 0) {
    166         ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), "
    167                "defaulting to 160 dpi", mDpiX, mDpiY);
    168         mDpiX = mDpiY = 160;
    169     }
    170 
    171     class Density {
    172         static int getDensityFromProperty(char const* propName) {
    173             char property[PROPERTY_VALUE_MAX];
    174             int density = 0;
    175             if (property_get(propName, property, NULL) > 0) {
    176                 density = atoi(property);
    177             }
    178             return density;
    179         }
    180     public:
    181         static int getEmuDensity() {
    182             return getDensityFromProperty("qemu.sf.lcd_density"); }
    183         static int getBuildDensity()  {
    184             return getDensityFromProperty("ro.sf.lcd_density"); }
    185     };
    186 
    187 
    188     // The density of the device is provided by a build property
    189     mDensity = Density::getBuildDensity() / 160.0f;
    190 
    191     if (mDensity == 0) {
    192         // the build doesn't provide a density -- this is wrong!
    193         // use xdpi instead
    194         ALOGE("ro.sf.lcd_density must be defined as a build property");
    195         mDensity = mDpiX / 160.0f;
    196     }
    197 
    198     if (Density::getEmuDensity()) {
    199         // if "qemu.sf.lcd_density" is specified, it overrides everything
    200         mDpiX = mDpiY = mDensity = Density::getEmuDensity();
    201         mDensity /= 160.0f;
    202     }
    203 
    204 
    205 
    206     /* FIXME: this is a temporary HACK until we are able to report the refresh rate
    207      * properly from the HAL. The WindowManagerService now relies on this value.
    208      */
    209 #ifndef REFRESH_RATE
    210     mRefreshRate = fbDev->fps;
    211 #else
    212     mRefreshRate = REFRESH_RATE;
    213 #warning "refresh rate set via makefile to REFRESH_RATE"
    214 #endif
    215 
    216     mRefreshPeriod = nsecs_t(1e9 / mRefreshRate);
    217 
    218     EGLint w, h, dummy;
    219     EGLint numConfigs=0;
    220     EGLSurface surface;
    221     EGLContext context;
    222     EGLBoolean result;
    223     status_t err;
    224 
    225     // initialize EGL
    226     EGLint attribs[] = {
    227             EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
    228             EGL_NONE,               0,
    229             EGL_NONE
    230     };
    231 
    232     // debug: disable h/w rendering
    233     char property[PROPERTY_VALUE_MAX];
    234     if (property_get("debug.sf.hw", property, NULL) > 0) {
    235         if (atoi(property) == 0) {
    236             ALOGW("H/W composition disabled");
    237             attribs[2] = EGL_CONFIG_CAVEAT;
    238             attribs[3] = EGL_SLOW_CONFIG;
    239         }
    240     }
    241 
    242     // TODO: all the extensions below should be queried through
    243     // eglGetProcAddress().
    244 
    245     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    246     eglInitialize(display, NULL, NULL);
    247     eglGetConfigs(display, NULL, 0, &numConfigs);
    248 
    249     EGLConfig config = NULL;
    250     err = selectConfigForPixelFormat(display, attribs, format, &config);
    251     ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
    252 
    253     EGLint r,g,b,a;
    254     eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
    255     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
    256     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
    257     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
    258 
    259     if (mNativeWindow->isUpdateOnDemand()) {
    260         mFlags |= PARTIAL_UPDATES;
    261     }
    262 
    263     if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
    264         if (dummy == EGL_SLOW_CONFIG)
    265             mFlags |= SLOW_CONFIG;
    266     }
    267 
    268     /*
    269      * Create our main surface
    270      */
    271 
    272     surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
    273     eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
    274     eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
    275 
    276     if (mFlags & PARTIAL_UPDATES) {
    277         // if we have partial updates, we definitely don't need to
    278         // preserve the backbuffer, which may be costly.
    279         eglSurfaceAttrib(display, surface,
    280                 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
    281     }
    282 
    283     /*
    284      * Create our OpenGL ES context
    285      */
    286 
    287     EGLint contextAttributes[] = {
    288 #ifdef EGL_IMG_context_priority
    289 #ifdef HAS_CONTEXT_PRIORITY
    290 #warning "using EGL_IMG_context_priority"
    291         EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
    292 #endif
    293 #endif
    294         EGL_NONE, EGL_NONE
    295     };
    296     context = eglCreateContext(display, config, NULL, contextAttributes);
    297 
    298     mDisplay = display;
    299     mConfig  = config;
    300     mSurface = surface;
    301     mContext = context;
    302     mFormat  = fbDev->format;
    303     mPageFlipCount = 0;
    304 
    305     /*
    306      * Gather OpenGL ES extensions
    307      */
    308 
    309     result = eglMakeCurrent(display, surface, surface, context);
    310     if (!result) {
    311         ALOGE("Couldn't create a working GLES context. check logs. exiting...");
    312         exit(0);
    313     }
    314 
    315     GLExtensions& extensions(GLExtensions::getInstance());
    316     extensions.initWithGLStrings(
    317             glGetString(GL_VENDOR),
    318             glGetString(GL_RENDERER),
    319             glGetString(GL_VERSION),
    320             glGetString(GL_EXTENSIONS),
    321             eglQueryString(display, EGL_VENDOR),
    322             eglQueryString(display, EGL_VERSION),
    323             eglQueryString(display, EGL_EXTENSIONS));
    324 
    325     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
    326     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
    327 
    328     ALOGI("EGL informations:");
    329     ALOGI("# of configs : %d", numConfigs);
    330     ALOGI("vendor    : %s", extensions.getEglVendor());
    331     ALOGI("version   : %s", extensions.getEglVersion());
    332     ALOGI("extensions: %s", extensions.getEglExtension());
    333     ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
    334     ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
    335 
    336     ALOGI("OpenGL informations:");
    337     ALOGI("vendor    : %s", extensions.getVendor());
    338     ALOGI("renderer  : %s", extensions.getRenderer());
    339     ALOGI("version   : %s", extensions.getVersion());
    340     ALOGI("extensions: %s", extensions.getExtension());
    341     ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
    342     ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
    343     ALOGI("flags = %08x", mFlags);
    344 
    345     // Unbind the context from this thread
    346     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    347 
    348 
    349     // initialize the H/W composer
    350     mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod);
    351     if (mHwc->initCheck() == NO_ERROR) {
    352         mHwc->setFrameBuffer(mDisplay, mSurface);
    353     }
    354 }
    355 
    356 void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) {
    357     Mutex::Autolock _l(mLock);
    358     mVSyncHandler = handler;
    359 }
    360 
    361 void DisplayHardware::eventControl(int event, int enabled) {
    362     if (event == EVENT_VSYNC) {
    363         mPowerHAL.vsyncHint(enabled);
    364     }
    365     mHwc->eventControl(event, enabled);
    366 }
    367 
    368 void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) {
    369     sp<VSyncHandler> handler;
    370     { // scope for the lock
    371         Mutex::Autolock _l(mLock);
    372         mLastHwVSync = timestamp;
    373         if (mVSyncHandler != NULL) {
    374             handler = mVSyncHandler.promote();
    375         }
    376     }
    377 
    378     if (handler != NULL) {
    379         handler->onVSyncReceived(dpy, timestamp);
    380     }
    381 }
    382 
    383 HWComposer& DisplayHardware::getHwComposer() const {
    384     return *mHwc;
    385 }
    386 
    387 /*
    388  * Clean up.  Throw out our local state.
    389  *
    390  * (It's entirely possible we'll never get here, since this is meant
    391  * for real hardware, which doesn't restart.)
    392  */
    393 
    394 void DisplayHardware::fini()
    395 {
    396     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    397     eglTerminate(mDisplay);
    398 }
    399 
    400 void DisplayHardware::releaseScreen() const
    401 {
    402     DisplayHardwareBase::releaseScreen();
    403     if (mHwc->initCheck() == NO_ERROR) {
    404         mHwc->release();
    405     }
    406 }
    407 
    408 void DisplayHardware::acquireScreen() const
    409 {
    410     DisplayHardwareBase::acquireScreen();
    411 }
    412 
    413 uint32_t DisplayHardware::getPageFlipCount() const {
    414     return mPageFlipCount;
    415 }
    416 
    417 nsecs_t DisplayHardware::getRefreshTimestamp() const {
    418     // this returns the last refresh timestamp.
    419     // if the last one is not available, we estimate it based on
    420     // the refresh period and whatever closest timestamp we have.
    421     Mutex::Autolock _l(mLock);
    422     nsecs_t now = systemTime(CLOCK_MONOTONIC);
    423     return now - ((now - mLastHwVSync) %  mRefreshPeriod);
    424 }
    425 
    426 nsecs_t DisplayHardware::getRefreshPeriod() const {
    427     return mRefreshPeriod;
    428 }
    429 
    430 status_t DisplayHardware::compositionComplete() const {
    431     return mNativeWindow->compositionComplete();
    432 }
    433 
    434 void DisplayHardware::flip(const Region& dirty) const
    435 {
    436     checkGLErrors();
    437 
    438     EGLDisplay dpy = mDisplay;
    439     EGLSurface surface = mSurface;
    440 
    441 #ifdef EGL_ANDROID_swap_rectangle
    442     if (mFlags & SWAP_RECTANGLE) {
    443         const Region newDirty(dirty.intersect(bounds()));
    444         const Rect b(newDirty.getBounds());
    445         eglSetSwapRectangleANDROID(dpy, surface,
    446                 b.left, b.top, b.width(), b.height());
    447     }
    448 #endif
    449 
    450     if (mFlags & PARTIAL_UPDATES) {
    451         mNativeWindow->setUpdateRectangle(dirty.getBounds());
    452     }
    453 
    454     mPageFlipCount++;
    455 
    456     if (mHwc->initCheck() == NO_ERROR) {
    457         mHwc->commit();
    458     } else {
    459         eglSwapBuffers(dpy, surface);
    460     }
    461     checkEGLErrors("eglSwapBuffers");
    462 
    463     // for debugging
    464     //glClearColor(1,0,0,0);
    465     //glClear(GL_COLOR_BUFFER_BIT);
    466 }
    467 
    468 uint32_t DisplayHardware::getFlags() const
    469 {
    470     return mFlags;
    471 }
    472 
    473 void DisplayHardware::makeCurrent() const
    474 {
    475     eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
    476 }
    477 
    478 void DisplayHardware::dump(String8& res) const
    479 {
    480     mNativeWindow->dump(res);
    481 }
    482