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