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(×tamp) < 0) { 378 // vsync not supported! 379 usleep( getDelayToNextVSyncUs(×tamp) ); 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