DisplayDevice.cpp revision 1b03149f3533db04e72e088d3fdd09d0087ca594
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 29#include <GLES/gl.h> 30#include <EGL/egl.h> 31#include <EGL/eglext.h> 32 33#include <hardware/gralloc.h> 34 35#include "DisplayHardware/FramebufferSurface.h" 36#include "DisplayHardware/DisplayHardwareBase.h" 37#include "DisplayHardware/HWComposer.h" 38 39#include "DisplayHardware.h" 40#include "GLExtensions.h" 41#include "SurfaceFlinger.h" 42 43using namespace android; 44 45 46static __attribute__((noinline)) 47void 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 ALOGE("GL error 0x%04x", int(error)); 55 } while(true); 56} 57 58static __attribute__((noinline)) 59void checkEGLErrors(const char* token) 60{ 61 struct EGLUtils { 62 static const char *strerror(EGLint err) { 63 switch (err){ 64 case EGL_SUCCESS: return "EGL_SUCCESS"; 65 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; 66 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; 67 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; 68 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; 69 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; 70 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; 71 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; 72 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; 73 case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; 74 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; 75 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; 76 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; 77 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; 78 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; 79 default: return "UNKNOWN"; 80 } 81 } 82 }; 83 84 EGLint error = eglGetError(); 85 if (error && error != EGL_SUCCESS) { 86 ALOGE("%s: EGL error 0x%04x (%s)", 87 token, int(error), EGLUtils::strerror(error)); 88 } 89} 90 91/* 92 * Initialize the display to the specified values. 93 * 94 */ 95 96DisplayHardware::DisplayHardware( 97 const sp<SurfaceFlinger>& flinger, 98 uint32_t dpy) 99 : DisplayHardwareBase(flinger, dpy), 100 mFlinger(flinger), mFlags(0), mHwc(0) 101{ 102 init(dpy); 103} 104 105DisplayHardware::~DisplayHardware() 106{ 107 fini(); 108} 109 110float DisplayHardware::getDpiX() const { return mDpiX; } 111float DisplayHardware::getDpiY() const { return mDpiY; } 112float DisplayHardware::getDensity() const { return mDensity; } 113float DisplayHardware::getRefreshRate() const { return mRefreshRate; } 114int DisplayHardware::getWidth() const { return mDisplayWidth; } 115int DisplayHardware::getHeight() const { return mDisplayHeight; } 116PixelFormat DisplayHardware::getFormat() const { return mFormat; } 117uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; } 118 119uint32_t DisplayHardware::getMaxViewportDims() const { 120 return mMaxViewportDims[0] < mMaxViewportDims[1] ? 121 mMaxViewportDims[0] : mMaxViewportDims[1]; 122} 123 124static status_t selectConfigForPixelFormat( 125 EGLDisplay dpy, 126 EGLint const* attrs, 127 PixelFormat format, 128 EGLConfig* outConfig) 129{ 130 EGLConfig config = NULL; 131 EGLint numConfigs = -1, n=0; 132 eglGetConfigs(dpy, NULL, 0, &numConfigs); 133 EGLConfig* const configs = new EGLConfig[numConfigs]; 134 eglChooseConfig(dpy, attrs, configs, numConfigs, &n); 135 for (int i=0 ; i<n ; i++) { 136 EGLint nativeVisualId = 0; 137 eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId); 138 if (nativeVisualId>0 && format == nativeVisualId) { 139 *outConfig = configs[i]; 140 delete [] configs; 141 return NO_ERROR; 142 } 143 } 144 delete [] configs; 145 return NAME_NOT_FOUND; 146} 147 148 149void DisplayHardware::init(uint32_t dpy) 150{ 151 mNativeWindow = new FramebufferSurface(); 152 framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); 153 if (!fbDev) { 154 ALOGE("Display subsystem failed to initialize. check logs. exiting..."); 155 exit(0); 156 } 157 158 int format; 159 ANativeWindow const * const window = mNativeWindow.get(); 160 window->query(window, NATIVE_WINDOW_FORMAT, &format); 161 mDpiX = mNativeWindow->xdpi; 162 mDpiY = mNativeWindow->ydpi; 163 mRefreshRate = fbDev->fps; 164 165 if (mDpiX == 0 || mDpiY == 0) { 166 ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), " 167 "defaulting to 160 dpi", mDpiX, mDpiY); 168 mDpiX = mDpiY = 160; 169 } 170 171 class Density { 172 static int getDensityFromProperty(char const* propName) { 173 char property[PROPERTY_VALUE_MAX]; 174 int density = 0; 175 if (property_get(propName, property, NULL) > 0) { 176 density = atoi(property); 177 } 178 return density; 179 } 180 public: 181 static int getEmuDensity() { 182 return getDensityFromProperty("qemu.sf.lcd_density"); } 183 static int getBuildDensity() { 184 return getDensityFromProperty("ro.sf.lcd_density"); } 185 }; 186 187 188 // The density of the device is provided by a build property 189 mDensity = Density::getBuildDensity() / 160.0f; 190 191 if (mDensity == 0) { 192 // the build doesn't provide a density -- this is wrong! 193 // use xdpi instead 194 ALOGE("ro.sf.lcd_density must be defined as a build property"); 195 mDensity = mDpiX / 160.0f; 196 } 197 198 if (Density::getEmuDensity()) { 199 // if "qemu.sf.lcd_density" is specified, it overrides everything 200 mDpiX = mDpiY = mDensity = Density::getEmuDensity(); 201 mDensity /= 160.0f; 202 } 203 204 205 206 /* FIXME: this is a temporary HACK until we are able to report the refresh rate 207 * properly from the HAL. The WindowManagerService now relies on this value. 208 */ 209#ifndef REFRESH_RATE 210 mRefreshRate = fbDev->fps; 211#else 212 mRefreshRate = REFRESH_RATE; 213#warning "refresh rate set via makefile to REFRESH_RATE" 214#endif 215 216 mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); 217 218 EGLint w, h, dummy; 219 EGLint numConfigs=0; 220 EGLSurface surface; 221 EGLContext context; 222 EGLBoolean result; 223 status_t err; 224 225 // initialize EGL 226 EGLint attribs[] = { 227 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 228 EGL_RECORDABLE_ANDROID, EGL_TRUE, 229 EGL_NONE 230 }; 231 232 // TODO: all the extensions below should be queried through 233 // eglGetProcAddress(). 234 235 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 236 eglInitialize(display, NULL, NULL); 237 eglGetConfigs(display, NULL, 0, &numConfigs); 238 239 EGLConfig config = NULL; 240 err = selectConfigForPixelFormat(display, attribs, format, &config); 241 if (err) { 242 // maybe we failed because of EGL_RECORDABLE_ANDROID 243 ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID"); 244 attribs[2] = EGL_NONE; 245 err = selectConfigForPixelFormat(display, attribs, format, &config); 246 } 247 248 ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); 249 250 EGLint r,g,b,a; 251 eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); 252 eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); 253 eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); 254 eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); 255 256 if (mNativeWindow->isUpdateOnDemand()) { 257 mFlags |= PARTIAL_UPDATES; 258 } 259 260 if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { 261 if (dummy == EGL_SLOW_CONFIG) 262 mFlags |= SLOW_CONFIG; 263 } 264 265 /* 266 * Create our main surface 267 */ 268 269 surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); 270 eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); 271 eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); 272 273 if (mFlags & PARTIAL_UPDATES) { 274 // if we have partial updates, we definitely don't need to 275 // preserve the backbuffer, which may be costly. 276 eglSurfaceAttrib(display, surface, 277 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); 278 } 279 280 /* 281 * Create our OpenGL ES context 282 */ 283 284 EGLint contextAttributes[] = { 285#ifdef EGL_IMG_context_priority 286#ifdef HAS_CONTEXT_PRIORITY 287#warning "using EGL_IMG_context_priority" 288 EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, 289#endif 290#endif 291 EGL_NONE, EGL_NONE 292 }; 293 context = eglCreateContext(display, config, NULL, contextAttributes); 294 295 mDisplay = display; 296 mConfig = config; 297 mSurface = surface; 298 mContext = context; 299 mFormat = fbDev->format; 300 mPageFlipCount = 0; 301 302 /* 303 * Gather OpenGL ES extensions 304 */ 305 306 result = eglMakeCurrent(display, surface, surface, context); 307 if (!result) { 308 ALOGE("Couldn't create a working GLES context. check logs. exiting..."); 309 exit(0); 310 } 311 312 GLExtensions& extensions(GLExtensions::getInstance()); 313 extensions.initWithGLStrings( 314 glGetString(GL_VENDOR), 315 glGetString(GL_RENDERER), 316 glGetString(GL_VERSION), 317 glGetString(GL_EXTENSIONS), 318 eglQueryString(display, EGL_VENDOR), 319 eglQueryString(display, EGL_VERSION), 320 eglQueryString(display, EGL_EXTENSIONS)); 321 322 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); 323 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); 324 325 ALOGI("EGL informations:"); 326 ALOGI("# of configs : %d", numConfigs); 327 ALOGI("vendor : %s", extensions.getEglVendor()); 328 ALOGI("version : %s", extensions.getEglVersion()); 329 ALOGI("extensions: %s", extensions.getEglExtension()); 330 ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); 331 ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); 332 333 ALOGI("OpenGL informations:"); 334 ALOGI("vendor : %s", extensions.getVendor()); 335 ALOGI("renderer : %s", extensions.getRenderer()); 336 ALOGI("version : %s", extensions.getVersion()); 337 ALOGI("extensions: %s", extensions.getExtension()); 338 ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); 339 ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]); 340 ALOGI("flags = %08x", mFlags); 341 342 // Unbind the context from this thread 343 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 344 345 346 // initialize the H/W composer 347 mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod); 348 if (mHwc->initCheck() == NO_ERROR) { 349 mHwc->setFrameBuffer(mDisplay, mSurface); 350 } 351 352 353 // initialize the display orientation transform. 354 // it's a constant that should come from the display driver. 355 int displayOrientation = ISurfaceComposer::eOrientationDefault; 356 char property[PROPERTY_VALUE_MAX]; 357 if (property_get("ro.sf.hwrotation", property, NULL) > 0) { 358 //displayOrientation 359 switch (atoi(property)) { 360 case 90: 361 displayOrientation = ISurfaceComposer::eOrientation90; 362 break; 363 case 270: 364 displayOrientation = ISurfaceComposer::eOrientation270; 365 break; 366 } 367 } 368 369 w = mDisplayWidth; 370 h = mDisplayHeight; 371 DisplayHardware::orientationToTransfrom(displayOrientation, w, h, 372 &mDisplayTransform); 373 if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) { 374 mLogicalDisplayWidth = h; 375 mLogicalDisplayHeight = w; 376 } else { 377 mLogicalDisplayWidth = w; 378 mLogicalDisplayHeight = h; 379 } 380 DisplayHardware::setOrientation(ISurfaceComposer::eOrientationDefault); 381} 382 383void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) { 384 Mutex::Autolock _l(mLock); 385 mVSyncHandler = handler; 386} 387 388void DisplayHardware::eventControl(int event, int enabled) { 389 if (event == EVENT_VSYNC) { 390 mPowerHAL.vsyncHint(enabled); 391 } 392 mHwc->eventControl(event, enabled); 393} 394 395void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) { 396 sp<VSyncHandler> handler; 397 { // scope for the lock 398 Mutex::Autolock _l(mLock); 399 mLastHwVSync = timestamp; 400 if (mVSyncHandler != NULL) { 401 handler = mVSyncHandler.promote(); 402 } 403 } 404 405 if (handler != NULL) { 406 handler->onVSyncReceived(dpy, timestamp); 407 } 408} 409 410HWComposer& DisplayHardware::getHwComposer() const { 411 return *mHwc; 412} 413 414/* 415 * Clean up. Throw out our local state. 416 * 417 * (It's entirely possible we'll never get here, since this is meant 418 * for real hardware, which doesn't restart.) 419 */ 420 421void DisplayHardware::fini() 422{ 423 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 424 eglTerminate(mDisplay); 425} 426 427void DisplayHardware::releaseScreen() const 428{ 429 DisplayHardwareBase::releaseScreen(); 430 if (mHwc->initCheck() == NO_ERROR) { 431 mHwc->release(); 432 } 433} 434 435void DisplayHardware::acquireScreen() const 436{ 437 DisplayHardwareBase::acquireScreen(); 438} 439 440uint32_t DisplayHardware::getPageFlipCount() const { 441 return mPageFlipCount; 442} 443 444nsecs_t DisplayHardware::getRefreshTimestamp() const { 445 // this returns the last refresh timestamp. 446 // if the last one is not available, we estimate it based on 447 // the refresh period and whatever closest timestamp we have. 448 Mutex::Autolock _l(mLock); 449 nsecs_t now = systemTime(CLOCK_MONOTONIC); 450 return now - ((now - mLastHwVSync) % mRefreshPeriod); 451} 452 453nsecs_t DisplayHardware::getRefreshPeriod() const { 454 return mRefreshPeriod; 455} 456 457status_t DisplayHardware::compositionComplete() const { 458 return mNativeWindow->compositionComplete(); 459} 460 461void DisplayHardware::flip(const Region& dirty) const 462{ 463 checkGLErrors(); 464 465 EGLDisplay dpy = mDisplay; 466 EGLSurface surface = mSurface; 467 468#ifdef EGL_ANDROID_swap_rectangle 469 if (mFlags & SWAP_RECTANGLE) { 470 const Region newDirty(dirty.intersect(bounds())); 471 const Rect b(newDirty.getBounds()); 472 eglSetSwapRectangleANDROID(dpy, surface, 473 b.left, b.top, b.width(), b.height()); 474 } 475#endif 476 477 if (mFlags & PARTIAL_UPDATES) { 478 mNativeWindow->setUpdateRectangle(dirty.getBounds()); 479 } 480 481 mPageFlipCount++; 482 483 if (mHwc->initCheck() == NO_ERROR) { 484 mHwc->commit(); 485 } else { 486 eglSwapBuffers(dpy, surface); 487 } 488 checkEGLErrors("eglSwapBuffers"); 489 490 // for debugging 491 //glClearColor(1,0,0,0); 492 //glClear(GL_COLOR_BUFFER_BIT); 493} 494 495uint32_t DisplayHardware::getFlags() const 496{ 497 return mFlags; 498} 499 500void DisplayHardware::makeCurrent() const 501{ 502 eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); 503} 504 505void DisplayHardware::dump(String8& res) const 506{ 507 mNativeWindow->dump(res); 508} 509 510// ---------------------------------------------------------------------------- 511 512status_t DisplayHardware::orientationToTransfrom( 513 int orientation, int w, int h, Transform* tr) 514{ 515 uint32_t flags = 0; 516 switch (orientation) { 517 case ISurfaceComposer::eOrientationDefault: 518 flags = Transform::ROT_0; 519 break; 520 case ISurfaceComposer::eOrientation90: 521 flags = Transform::ROT_90; 522 break; 523 case ISurfaceComposer::eOrientation180: 524 flags = Transform::ROT_180; 525 break; 526 case ISurfaceComposer::eOrientation270: 527 flags = Transform::ROT_270; 528 break; 529 default: 530 return BAD_VALUE; 531 } 532 tr->set(flags, w, h); 533 return NO_ERROR; 534} 535 536status_t DisplayHardware::setOrientation(int orientation) 537{ 538 // If the rotation can be handled in hardware, this is where 539 // the magic should happen. 540 541 const int w = mLogicalDisplayWidth; 542 const int h = mLogicalDisplayHeight; 543 mUserDisplayWidth = w; 544 mUserDisplayHeight = h; 545 546 Transform orientationTransform; 547 DisplayHardware::orientationToTransfrom(orientation, w, h, 548 &orientationTransform); 549 if (orientation & ISurfaceComposer::eOrientationSwapMask) { 550 mUserDisplayWidth = h; 551 mUserDisplayHeight = w; 552 } 553 554 mOrientation = orientation; 555 mGlobalTransform = mDisplayTransform * orientationTransform; 556 return NO_ERROR; 557} 558