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/copybit.h>
     40 #include <hardware/overlay.h>
     41 #include <hardware/gralloc.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         LOGE("GL error 0x%04x", int(error));
     55     } while(true);
     56 }
     57 
     58 static __attribute__((noinline))
     59 void checkEGLErrors(const char* token)
     60 {
     61     EGLint error = eglGetError();
     62     if (error && error != EGL_SUCCESS) {
     63         LOGE("%s: EGL error 0x%04x (%s)",
     64                 token, int(error), EGLUtils::strerror(error));
     65     }
     66 }
     67 
     68 /*
     69  * Initialize the display to the specified values.
     70  *
     71  */
     72 
     73 DisplayHardware::DisplayHardware(
     74         const sp<SurfaceFlinger>& flinger,
     75         uint32_t dpy)
     76     : DisplayHardwareBase(flinger, dpy)
     77 {
     78     init(dpy);
     79 }
     80 
     81 DisplayHardware::~DisplayHardware()
     82 {
     83     fini();
     84 }
     85 
     86 float DisplayHardware::getDpiX() const          { return mDpiX; }
     87 float DisplayHardware::getDpiY() const          { return mDpiY; }
     88 float DisplayHardware::getDensity() const       { return mDensity; }
     89 float DisplayHardware::getRefreshRate() const   { return mRefreshRate; }
     90 int DisplayHardware::getWidth() const           { return mWidth; }
     91 int DisplayHardware::getHeight() const          { return mHeight; }
     92 PixelFormat DisplayHardware::getFormat() const  { return mFormat; }
     93 uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
     94 uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; }
     95 
     96 void DisplayHardware::init(uint32_t dpy)
     97 {
     98     mNativeWindow = new FramebufferNativeWindow();
     99     framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
    100 
    101     mOverlayEngine = NULL;
    102     hw_module_t const* module;
    103     if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
    104         overlay_control_open(module, &mOverlayEngine);
    105     }
    106 
    107     // initialize EGL
    108     EGLint attribs[] = {
    109             EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
    110             EGL_NONE,           0,
    111             EGL_NONE
    112     };
    113 
    114     // debug: disable h/w rendering
    115     char property[PROPERTY_VALUE_MAX];
    116     if (property_get("debug.sf.hw", property, NULL) > 0) {
    117         if (atoi(property) == 0) {
    118             LOGW("H/W composition disabled");
    119             attribs[2] = EGL_CONFIG_CAVEAT;
    120             attribs[3] = EGL_SLOW_CONFIG;
    121         }
    122     }
    123 
    124     EGLint w, h, dummy;
    125     EGLint numConfigs=0;
    126     EGLSurface surface;
    127     EGLContext context;
    128     mFlags = CACHED_BUFFERS;
    129 
    130     // TODO: all the extensions below should be queried through
    131     // eglGetProcAddress().
    132 
    133     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    134     eglInitialize(display, NULL, NULL);
    135     eglGetConfigs(display, NULL, 0, &numConfigs);
    136 
    137     EGLConfig config;
    138     status_t err = EGLUtils::selectConfigForNativeWindow(
    139             display, attribs, mNativeWindow.get(), &config);
    140     LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
    141 
    142     EGLint r,g,b,a;
    143     eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
    144     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
    145     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
    146     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
    147 
    148     /*
    149      * Gather EGL extensions
    150      */
    151 
    152     const char* const egl_extensions = eglQueryString(
    153             display, EGL_EXTENSIONS);
    154 
    155     LOGI("EGL informations:");
    156     LOGI("# of configs : %d", numConfigs);
    157     LOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
    158     LOGI("version   : %s", eglQueryString(display, EGL_VERSION));
    159     LOGI("extensions: %s", egl_extensions);
    160     LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
    161     LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
    162 
    163 
    164     if (mNativeWindow->isUpdateOnDemand()) {
    165         mFlags |= PARTIAL_UPDATES;
    166     }
    167 
    168     if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
    169         if (dummy == EGL_SLOW_CONFIG)
    170             mFlags |= SLOW_CONFIG;
    171     }
    172 
    173     /*
    174      * Create our main surface
    175      */
    176 
    177     surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
    178 
    179     if (mFlags & PARTIAL_UPDATES) {
    180         // if we have partial updates, we definitely don't need to
    181         // preserve the backbuffer, which may be costly.
    182         eglSurfaceAttrib(display, surface,
    183                 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
    184     }
    185 
    186     if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
    187         if (dummy == EGL_BUFFER_PRESERVED) {
    188             mFlags |= BUFFER_PRESERVED;
    189         }
    190     }
    191 
    192     eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
    193     eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
    194 
    195 #ifdef EGL_ANDROID_swap_rectangle
    196     if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) {
    197         if (eglSetSwapRectangleANDROID(display, surface,
    198                 0, 0, mWidth, mHeight) == EGL_TRUE) {
    199             // This could fail if this extension is not supported by this
    200             // specific surface (of config)
    201             mFlags |= SWAP_RECTANGLE;
    202         }
    203     }
    204     // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
    205     // choose PARTIAL_UPDATES, which should be more efficient
    206     if (mFlags & PARTIAL_UPDATES)
    207         mFlags &= ~SWAP_RECTANGLE;
    208 #endif
    209 
    210 
    211     LOGI("flags     : %08x", mFlags);
    212 
    213     mDpiX = mNativeWindow->xdpi;
    214     mDpiY = mNativeWindow->ydpi;
    215     mRefreshRate = fbDev->fps;
    216 
    217     /* Read density from build-specific ro.sf.lcd_density property
    218      * except if it is overridden by qemu.sf.lcd_density.
    219      */
    220     if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
    221         if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
    222             LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
    223             strcpy(property, "160");
    224         }
    225     } else {
    226         /* for the emulator case, reset the dpi values too */
    227         mDpiX = mDpiY = atoi(property);
    228     }
    229     mDensity = atoi(property) * (1.0f/160.0f);
    230 
    231 
    232     /*
    233      * Create our OpenGL ES context
    234      */
    235 
    236     context = eglCreateContext(display, config, NULL, NULL);
    237 
    238     /*
    239      * Gather OpenGL ES extensions
    240      */
    241 
    242     eglMakeCurrent(display, surface, surface, context);
    243     const char* const  gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
    244     const char* const  gl_renderer = (const char*)glGetString(GL_RENDERER);
    245     LOGI("OpenGL informations:");
    246     LOGI("vendor    : %s", glGetString(GL_VENDOR));
    247     LOGI("renderer  : %s", gl_renderer);
    248     LOGI("version   : %s", glGetString(GL_VERSION));
    249     LOGI("extensions: %s", gl_extensions);
    250 
    251     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
    252     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
    253     LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
    254     LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
    255 
    256 #if 0
    257     // for drivers that don't have proper support for flushing cached buffers
    258     // on gralloc unlock, uncomment this block and test for the specific
    259     // renderer substring
    260     if (strstr(gl_renderer, "<some vendor string>")) {
    261         LOGD("Assuming uncached graphics buffers.");
    262         mFlags &= ~CACHED_BUFFERS;
    263     }
    264 #endif
    265 
    266     if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
    267         mFlags |= NPOT_EXTENSION;
    268     }
    269     if (strstr(gl_extensions, "GL_OES_draw_texture")) {
    270         mFlags |= DRAW_TEXTURE_EXTENSION;
    271     }
    272 #ifdef EGL_ANDROID_image_native_buffer
    273     if (strstr( gl_extensions, "GL_OES_EGL_image") &&
    274         (strstr(egl_extensions, "EGL_KHR_image_base") ||
    275                 strstr(egl_extensions, "EGL_KHR_image")) &&
    276         strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
    277         mFlags |= DIRECT_TEXTURE;
    278     }
    279 #else
    280 #warning "EGL_ANDROID_image_native_buffer not supported"
    281 #endif
    282 
    283 
    284     // Unbind the context from this thread
    285     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    286 
    287     mDisplay = display;
    288     mConfig  = config;
    289     mSurface = surface;
    290     mContext = context;
    291     mFormat  = fbDev->format;
    292     mPageFlipCount = 0;
    293 }
    294 
    295 /*
    296  * Clean up.  Throw out our local state.
    297  *
    298  * (It's entirely possible we'll never get here, since this is meant
    299  * for real hardware, which doesn't restart.)
    300  */
    301 
    302 void DisplayHardware::fini()
    303 {
    304     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    305     eglTerminate(mDisplay);
    306     overlay_control_close(mOverlayEngine);
    307 }
    308 
    309 void DisplayHardware::releaseScreen() const
    310 {
    311     DisplayHardwareBase::releaseScreen();
    312 }
    313 
    314 void DisplayHardware::acquireScreen() const
    315 {
    316     DisplayHardwareBase::acquireScreen();
    317 }
    318 
    319 uint32_t DisplayHardware::getPageFlipCount() const {
    320     return mPageFlipCount;
    321 }
    322 
    323 status_t DisplayHardware::compositionComplete() const {
    324     return mNativeWindow->compositionComplete();
    325 }
    326 
    327 void DisplayHardware::flip(const Region& dirty) const
    328 {
    329     checkGLErrors();
    330 
    331     EGLDisplay dpy = mDisplay;
    332     EGLSurface surface = mSurface;
    333 
    334 #ifdef EGL_ANDROID_swap_rectangle
    335     if (mFlags & SWAP_RECTANGLE) {
    336         const Region newDirty(dirty.intersect(bounds()));
    337         const Rect b(newDirty.getBounds());
    338         eglSetSwapRectangleANDROID(dpy, surface,
    339                 b.left, b.top, b.width(), b.height());
    340     }
    341 #endif
    342 
    343     if (mFlags & PARTIAL_UPDATES) {
    344         mNativeWindow->setUpdateRectangle(dirty.getBounds());
    345     }
    346 
    347     mPageFlipCount++;
    348     eglSwapBuffers(dpy, surface);
    349     checkEGLErrors("eglSwapBuffers");
    350 
    351     // for debugging
    352     //glClearColor(1,0,0,0);
    353     //glClear(GL_COLOR_BUFFER_BIT);
    354 }
    355 
    356 uint32_t DisplayHardware::getFlags() const
    357 {
    358     return mFlags;
    359 }
    360 
    361 void DisplayHardware::makeCurrent() const
    362 {
    363     eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
    364 }
    365