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 "DisplayHardware/DisplayHardware.h" 35 36 #include <hardware/gralloc.h> 37 38 #include "DisplayHardwareBase.h" 39 #include "GLExtensions.h" 40 #include "HWComposer.h" 41 #include "SurfaceFlinger.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 ALOGE("GL error 0x%04x", int(error)); 55 } while(true); 56 } 57 58 static __attribute__((noinline)) 59 void 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 96 DisplayHardware::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 105 DisplayHardware::~DisplayHardware() 106 { 107 fini(); 108 } 109 110 float DisplayHardware::getDpiX() const { return mDpiX; } 111 float DisplayHardware::getDpiY() const { return mDpiY; } 112 float DisplayHardware::getDensity() const { return mDensity; } 113 float DisplayHardware::getRefreshRate() const { return mRefreshRate; } 114 int DisplayHardware::getWidth() const { return mWidth; } 115 int DisplayHardware::getHeight() const { return mHeight; } 116 PixelFormat DisplayHardware::getFormat() const { return mFormat; } 117 uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; } 118 119 uint32_t DisplayHardware::getMaxViewportDims() const { 120 return mMaxViewportDims[0] < mMaxViewportDims[1] ? 121 mMaxViewportDims[0] : mMaxViewportDims[1]; 122 } 123 124 static 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 149 void DisplayHardware::init(uint32_t dpy) 150 { 151 mNativeWindow = new FramebufferNativeWindow(); 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_NONE, 0, 229 EGL_NONE 230 }; 231 232 // debug: disable h/w rendering 233 char property[PROPERTY_VALUE_MAX]; 234 if (property_get("debug.sf.hw", property, NULL) > 0) { 235 if (atoi(property) == 0) { 236 ALOGW("H/W composition disabled"); 237 attribs[2] = EGL_CONFIG_CAVEAT; 238 attribs[3] = EGL_SLOW_CONFIG; 239 } 240 } 241 242 // TODO: all the extensions below should be queried through 243 // eglGetProcAddress(). 244 245 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 246 eglInitialize(display, NULL, NULL); 247 eglGetConfigs(display, NULL, 0, &numConfigs); 248 249 EGLConfig config = NULL; 250 err = selectConfigForPixelFormat(display, attribs, format, &config); 251 ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); 252 253 EGLint r,g,b,a; 254 eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); 255 eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); 256 eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); 257 eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); 258 259 if (mNativeWindow->isUpdateOnDemand()) { 260 mFlags |= PARTIAL_UPDATES; 261 } 262 263 if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { 264 if (dummy == EGL_SLOW_CONFIG) 265 mFlags |= SLOW_CONFIG; 266 } 267 268 /* 269 * Create our main surface 270 */ 271 272 surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); 273 eglQuerySurface(display, surface, EGL_WIDTH, &mWidth); 274 eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); 275 276 if (mFlags & PARTIAL_UPDATES) { 277 // if we have partial updates, we definitely don't need to 278 // preserve the backbuffer, which may be costly. 279 eglSurfaceAttrib(display, surface, 280 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); 281 } 282 283 /* 284 * Create our OpenGL ES context 285 */ 286 287 EGLint contextAttributes[] = { 288 #ifdef EGL_IMG_context_priority 289 #ifdef HAS_CONTEXT_PRIORITY 290 #warning "using EGL_IMG_context_priority" 291 EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, 292 #endif 293 #endif 294 EGL_NONE, EGL_NONE 295 }; 296 context = eglCreateContext(display, config, NULL, contextAttributes); 297 298 mDisplay = display; 299 mConfig = config; 300 mSurface = surface; 301 mContext = context; 302 mFormat = fbDev->format; 303 mPageFlipCount = 0; 304 305 /* 306 * Gather OpenGL ES extensions 307 */ 308 309 result = eglMakeCurrent(display, surface, surface, context); 310 if (!result) { 311 ALOGE("Couldn't create a working GLES context. check logs. exiting..."); 312 exit(0); 313 } 314 315 GLExtensions& extensions(GLExtensions::getInstance()); 316 extensions.initWithGLStrings( 317 glGetString(GL_VENDOR), 318 glGetString(GL_RENDERER), 319 glGetString(GL_VERSION), 320 glGetString(GL_EXTENSIONS), 321 eglQueryString(display, EGL_VENDOR), 322 eglQueryString(display, EGL_VERSION), 323 eglQueryString(display, EGL_EXTENSIONS)); 324 325 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); 326 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); 327 328 ALOGI("EGL informations:"); 329 ALOGI("# of configs : %d", numConfigs); 330 ALOGI("vendor : %s", extensions.getEglVendor()); 331 ALOGI("version : %s", extensions.getEglVersion()); 332 ALOGI("extensions: %s", extensions.getEglExtension()); 333 ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); 334 ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); 335 336 ALOGI("OpenGL informations:"); 337 ALOGI("vendor : %s", extensions.getVendor()); 338 ALOGI("renderer : %s", extensions.getRenderer()); 339 ALOGI("version : %s", extensions.getVersion()); 340 ALOGI("extensions: %s", extensions.getExtension()); 341 ALOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); 342 ALOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]); 343 ALOGI("flags = %08x", mFlags); 344 345 // Unbind the context from this thread 346 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 347 348 349 // initialize the H/W composer 350 mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod); 351 if (mHwc->initCheck() == NO_ERROR) { 352 mHwc->setFrameBuffer(mDisplay, mSurface); 353 } 354 } 355 356 void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) { 357 Mutex::Autolock _l(mLock); 358 mVSyncHandler = handler; 359 } 360 361 void DisplayHardware::eventControl(int event, int enabled) { 362 if (event == EVENT_VSYNC) { 363 mPowerHAL.vsyncHint(enabled); 364 } 365 mHwc->eventControl(event, enabled); 366 } 367 368 void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) { 369 sp<VSyncHandler> handler; 370 { // scope for the lock 371 Mutex::Autolock _l(mLock); 372 mLastHwVSync = timestamp; 373 if (mVSyncHandler != NULL) { 374 handler = mVSyncHandler.promote(); 375 } 376 } 377 378 if (handler != NULL) { 379 handler->onVSyncReceived(dpy, timestamp); 380 } 381 } 382 383 HWComposer& DisplayHardware::getHwComposer() const { 384 return *mHwc; 385 } 386 387 /* 388 * Clean up. Throw out our local state. 389 * 390 * (It's entirely possible we'll never get here, since this is meant 391 * for real hardware, which doesn't restart.) 392 */ 393 394 void DisplayHardware::fini() 395 { 396 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 397 eglTerminate(mDisplay); 398 } 399 400 void DisplayHardware::releaseScreen() const 401 { 402 DisplayHardwareBase::releaseScreen(); 403 if (mHwc->initCheck() == NO_ERROR) { 404 mHwc->release(); 405 } 406 } 407 408 void DisplayHardware::acquireScreen() const 409 { 410 DisplayHardwareBase::acquireScreen(); 411 } 412 413 uint32_t DisplayHardware::getPageFlipCount() const { 414 return mPageFlipCount; 415 } 416 417 nsecs_t DisplayHardware::getRefreshTimestamp() const { 418 // this returns the last refresh timestamp. 419 // if the last one is not available, we estimate it based on 420 // the refresh period and whatever closest timestamp we have. 421 Mutex::Autolock _l(mLock); 422 nsecs_t now = systemTime(CLOCK_MONOTONIC); 423 return now - ((now - mLastHwVSync) % mRefreshPeriod); 424 } 425 426 nsecs_t DisplayHardware::getRefreshPeriod() const { 427 return mRefreshPeriod; 428 } 429 430 status_t DisplayHardware::compositionComplete() const { 431 return mNativeWindow->compositionComplete(); 432 } 433 434 void DisplayHardware::flip(const Region& dirty) const 435 { 436 checkGLErrors(); 437 438 EGLDisplay dpy = mDisplay; 439 EGLSurface surface = mSurface; 440 441 #ifdef EGL_ANDROID_swap_rectangle 442 if (mFlags & SWAP_RECTANGLE) { 443 const Region newDirty(dirty.intersect(bounds())); 444 const Rect b(newDirty.getBounds()); 445 eglSetSwapRectangleANDROID(dpy, surface, 446 b.left, b.top, b.width(), b.height()); 447 } 448 #endif 449 450 if (mFlags & PARTIAL_UPDATES) { 451 mNativeWindow->setUpdateRectangle(dirty.getBounds()); 452 } 453 454 mPageFlipCount++; 455 456 if (mHwc->initCheck() == NO_ERROR) { 457 mHwc->commit(); 458 } else { 459 eglSwapBuffers(dpy, surface); 460 } 461 checkEGLErrors("eglSwapBuffers"); 462 463 // for debugging 464 //glClearColor(1,0,0,0); 465 //glClear(GL_COLOR_BUFFER_BIT); 466 } 467 468 uint32_t DisplayHardware::getFlags() const 469 { 470 return mFlags; 471 } 472 473 void DisplayHardware::makeCurrent() const 474 { 475 eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); 476 } 477 478 void DisplayHardware::dump(String8& res) const 479 { 480 mNativeWindow->dump(res); 481 } 482