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