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