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 #include <ui/EGLUtils.h>
     30 
     31 #include <GLES/gl.h>
     32 #include <EGL/egl.h>
     33 #include <EGL/eglext.h>
     34 
     35 #include <pixelflinger/pixelflinger.h>
     36 
     37 #include "DisplayHardware/DisplayHardware.h"
     38 
     39 #include <hardware/gralloc.h>
     40 
     41 #include "GLExtensions.h"
     42 #include "HWComposer.h"
     43 #include "SurfaceFlinger.h"
     44 
     45 using namespace android;
     46 
     47 
     48 static __attribute__((noinline))
     49 void checkGLErrors()
     50 {
     51     do {
     52         // there could be more than one error flag
     53         GLenum error = glGetError();
     54         if (error == GL_NO_ERROR)
     55             break;
     56         LOGE("GL error 0x%04x", int(error));
     57     } while(true);
     58 }
     59 
     60 static __attribute__((noinline))
     61 void checkEGLErrors(const char* token)
     62 {
     63     EGLint error = eglGetError();
     64     if (error && error != EGL_SUCCESS) {
     65         LOGE("%s: EGL error 0x%04x (%s)",
     66                 token, int(error), EGLUtils::strerror(error));
     67     }
     68 }
     69 
     70 /*
     71  * Initialize the display to the specified values.
     72  *
     73  */
     74 
     75 DisplayHardware::DisplayHardware(
     76         const sp<SurfaceFlinger>& flinger,
     77         uint32_t dpy)
     78     : DisplayHardwareBase(flinger, dpy),
     79       mFlinger(flinger), mFlags(0), mHwc(0)
     80 {
     81     init(dpy);
     82 }
     83 
     84 DisplayHardware::~DisplayHardware()
     85 {
     86     fini();
     87 }
     88 
     89 float DisplayHardware::getDpiX() const          { return mDpiX; }
     90 float DisplayHardware::getDpiY() const          { return mDpiY; }
     91 float DisplayHardware::getDensity() const       { return mDensity; }
     92 float DisplayHardware::getRefreshRate() const   { return mRefreshRate; }
     93 int DisplayHardware::getWidth() const           { return mWidth; }
     94 int DisplayHardware::getHeight() const          { return mHeight; }
     95 PixelFormat DisplayHardware::getFormat() const  { return mFormat; }
     96 uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
     97 
     98 uint32_t DisplayHardware::getMaxViewportDims() const {
     99     return mMaxViewportDims[0] < mMaxViewportDims[1] ?
    100             mMaxViewportDims[0] : mMaxViewportDims[1];
    101 }
    102 
    103 static status_t selectConfigForPixelFormat(
    104         EGLDisplay dpy,
    105         EGLint const* attrs,
    106         PixelFormat format,
    107         EGLConfig* outConfig)
    108 {
    109     EGLConfig config = NULL;
    110     EGLint numConfigs = -1, n=0;
    111     eglGetConfigs(dpy, NULL, 0, &numConfigs);
    112     EGLConfig* const configs = new EGLConfig[numConfigs];
    113     eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
    114     for (int i=0 ; i<n ; i++) {
    115         EGLint nativeVisualId = 0;
    116         eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
    117         if (nativeVisualId>0 && format == nativeVisualId) {
    118             *outConfig = configs[i];
    119             delete [] configs;
    120             return NO_ERROR;
    121         }
    122     }
    123     delete [] configs;
    124     return NAME_NOT_FOUND;
    125 }
    126 
    127 
    128 void DisplayHardware::init(uint32_t dpy)
    129 {
    130     mNativeWindow = new FramebufferNativeWindow();
    131     framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
    132     if (!fbDev) {
    133         LOGE("Display subsystem failed to initialize. check logs. exiting...");
    134         exit(0);
    135     }
    136 
    137     int format;
    138     ANativeWindow const * const window = mNativeWindow.get();
    139     window->query(window, NATIVE_WINDOW_FORMAT, &format);
    140     mDpiX = mNativeWindow->xdpi;
    141     mDpiY = mNativeWindow->ydpi;
    142     mRefreshRate = fbDev->fps;
    143 
    144 
    145 /* FIXME: this is a temporary HACK until we are able to report the refresh rate
    146  * properly from the HAL. The WindowManagerService now relies on this value.
    147  */
    148 #ifndef REFRESH_RATE
    149     mRefreshRate = fbDev->fps;
    150 #else
    151     mRefreshRate = REFRESH_RATE;
    152 #warning "refresh rate set via makefile to REFRESH_RATE"
    153 #endif
    154 
    155     EGLint w, h, dummy;
    156     EGLint numConfigs=0;
    157     EGLSurface surface;
    158     EGLContext context;
    159     EGLBoolean result;
    160     status_t err;
    161 
    162     // initialize EGL
    163     EGLint attribs[] = {
    164             EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
    165             EGL_NONE,               0,
    166             EGL_NONE
    167     };
    168 
    169     // debug: disable h/w rendering
    170     char property[PROPERTY_VALUE_MAX];
    171     if (property_get("debug.sf.hw", property, NULL) > 0) {
    172         if (atoi(property) == 0) {
    173             LOGW("H/W composition disabled");
    174             attribs[2] = EGL_CONFIG_CAVEAT;
    175             attribs[3] = EGL_SLOW_CONFIG;
    176         }
    177     }
    178 
    179     // TODO: all the extensions below should be queried through
    180     // eglGetProcAddress().
    181 
    182     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    183     eglInitialize(display, NULL, NULL);
    184     eglGetConfigs(display, NULL, 0, &numConfigs);
    185 
    186     EGLConfig config = NULL;
    187     err = selectConfigForPixelFormat(display, attribs, format, &config);
    188     LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
    189 
    190     EGLint r,g,b,a;
    191     eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
    192     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
    193     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
    194     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
    195 
    196     if (mNativeWindow->isUpdateOnDemand()) {
    197         mFlags |= PARTIAL_UPDATES;
    198     }
    199 
    200     if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
    201         if (dummy == EGL_SLOW_CONFIG)
    202             mFlags |= SLOW_CONFIG;
    203     }
    204 
    205     /*
    206      * Create our main surface
    207      */
    208 
    209     surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
    210     eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
    211     eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
    212 
    213     if (mFlags & PARTIAL_UPDATES) {
    214         // if we have partial updates, we definitely don't need to
    215         // preserve the backbuffer, which may be costly.
    216         eglSurfaceAttrib(display, surface,
    217                 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
    218     }
    219 
    220     if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
    221         if (dummy == EGL_BUFFER_PRESERVED) {
    222             mFlags |= BUFFER_PRESERVED;
    223         }
    224     }
    225 
    226     /* Read density from build-specific ro.sf.lcd_density property
    227      * except if it is overridden by qemu.sf.lcd_density.
    228      */
    229     if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
    230         if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
    231             LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
    232             strcpy(property, "160");
    233         }
    234     } else {
    235         /* for the emulator case, reset the dpi values too */
    236         mDpiX = mDpiY = atoi(property);
    237     }
    238     mDensity = atoi(property) * (1.0f/160.0f);
    239 
    240 
    241     /*
    242      * Create our OpenGL ES context
    243      */
    244 
    245 
    246     EGLint contextAttributes[] = {
    247 #ifdef EGL_IMG_context_priority
    248 #ifdef HAS_CONTEXT_PRIORITY
    249 #warning "using EGL_IMG_context_priority"
    250         EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
    251 #endif
    252 #endif
    253         EGL_NONE, EGL_NONE
    254     };
    255     context = eglCreateContext(display, config, NULL, contextAttributes);
    256 
    257     mDisplay = display;
    258     mConfig  = config;
    259     mSurface = surface;
    260     mContext = context;
    261     mFormat  = fbDev->format;
    262     mPageFlipCount = 0;
    263 
    264     /*
    265      * Gather OpenGL ES extensions
    266      */
    267 
    268     result = eglMakeCurrent(display, surface, surface, context);
    269     if (!result) {
    270         LOGE("Couldn't create a working GLES context. check logs. exiting...");
    271         exit(0);
    272     }
    273 
    274     GLExtensions& extensions(GLExtensions::getInstance());
    275     extensions.initWithGLStrings(
    276             glGetString(GL_VENDOR),
    277             glGetString(GL_RENDERER),
    278             glGetString(GL_VERSION),
    279             glGetString(GL_EXTENSIONS),
    280             eglQueryString(display, EGL_VENDOR),
    281             eglQueryString(display, EGL_VERSION),
    282             eglQueryString(display, EGL_EXTENSIONS));
    283 
    284     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
    285     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
    286 
    287     LOGI("EGL informations:");
    288     LOGI("# of configs : %d", numConfigs);
    289     LOGI("vendor    : %s", extensions.getEglVendor());
    290     LOGI("version   : %s", extensions.getEglVersion());
    291     LOGI("extensions: %s", extensions.getEglExtension());
    292     LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
    293     LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
    294 
    295     LOGI("OpenGL informations:");
    296     LOGI("vendor    : %s", extensions.getVendor());
    297     LOGI("renderer  : %s", extensions.getRenderer());
    298     LOGI("version   : %s", extensions.getVersion());
    299     LOGI("extensions: %s", extensions.getExtension());
    300     LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
    301     LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
    302     LOGI("flags = %08x", mFlags);
    303 
    304     // Unbind the context from this thread
    305     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    306 
    307 
    308     // initialize the H/W composer
    309     mHwc = new HWComposer(mFlinger);
    310     if (mHwc->initCheck() == NO_ERROR) {
    311         mHwc->setFrameBuffer(mDisplay, mSurface);
    312     }
    313 }
    314 
    315 HWComposer& DisplayHardware::getHwComposer() const {
    316     return *mHwc;
    317 }
    318 
    319 /*
    320  * Clean up.  Throw out our local state.
    321  *
    322  * (It's entirely possible we'll never get here, since this is meant
    323  * for real hardware, which doesn't restart.)
    324  */
    325 
    326 void DisplayHardware::fini()
    327 {
    328     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    329     eglTerminate(mDisplay);
    330 }
    331 
    332 void DisplayHardware::releaseScreen() const
    333 {
    334     DisplayHardwareBase::releaseScreen();
    335     if (mHwc->initCheck() == NO_ERROR) {
    336         mHwc->release();
    337     }
    338 }
    339 
    340 void DisplayHardware::acquireScreen() const
    341 {
    342     DisplayHardwareBase::acquireScreen();
    343 }
    344 
    345 uint32_t DisplayHardware::getPageFlipCount() const {
    346     return mPageFlipCount;
    347 }
    348 
    349 status_t DisplayHardware::compositionComplete() const {
    350     return mNativeWindow->compositionComplete();
    351 }
    352 
    353 int DisplayHardware::getCurrentBufferIndex() const {
    354     return mNativeWindow->getCurrentBufferIndex();
    355 }
    356 
    357 void DisplayHardware::flip(const Region& dirty) const
    358 {
    359     checkGLErrors();
    360 
    361     EGLDisplay dpy = mDisplay;
    362     EGLSurface surface = mSurface;
    363 
    364 #ifdef EGL_ANDROID_swap_rectangle
    365     if (mFlags & SWAP_RECTANGLE) {
    366         const Region newDirty(dirty.intersect(bounds()));
    367         const Rect b(newDirty.getBounds());
    368         eglSetSwapRectangleANDROID(dpy, surface,
    369                 b.left, b.top, b.width(), b.height());
    370     }
    371 #endif
    372 
    373     if (mFlags & PARTIAL_UPDATES) {
    374         mNativeWindow->setUpdateRectangle(dirty.getBounds());
    375     }
    376 
    377     mPageFlipCount++;
    378 
    379     if (mHwc->initCheck() == NO_ERROR) {
    380         mHwc->commit();
    381     } else {
    382         eglSwapBuffers(dpy, surface);
    383     }
    384     checkEGLErrors("eglSwapBuffers");
    385 
    386     // for debugging
    387     //glClearColor(1,0,0,0);
    388     //glClear(GL_COLOR_BUFFER_BIT);
    389 }
    390 
    391 uint32_t DisplayHardware::getFlags() const
    392 {
    393     return mFlags;
    394 }
    395 
    396 void DisplayHardware::makeCurrent() const
    397 {
    398     eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
    399 }
    400 
    401 void DisplayHardware::dump(String8& res) const
    402 {
    403     mNativeWindow->dump(res);
    404 }
    405