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