DisplayHardware.cpp revision 1d21a9cafc534c34a2f28c985c4c7aa176d0e67b
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/overlay.h> 40#include <hardware/gralloc.h> 41 42#include "GLExtensions.h" 43#include "HWComposer.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 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; } 97uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; } 98 99void DisplayHardware::init(uint32_t dpy) 100{ 101 mNativeWindow = new FramebufferNativeWindow(); 102 framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); 103 mDpiX = mNativeWindow->xdpi; 104 mDpiY = mNativeWindow->ydpi; 105 mRefreshRate = fbDev->fps; 106 107 mOverlayEngine = NULL; 108 hw_module_t const* module; 109 if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) { 110 overlay_control_open(module, &mOverlayEngine); 111 } 112 113 EGLint w, h, dummy; 114 EGLint numConfigs=0; 115 EGLSurface surface; 116 EGLContext context; 117 118 // initialize EGL 119 EGLint attribs[] = { 120 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 121 EGL_NONE, 0, 122 EGL_NONE 123 }; 124 125 // debug: disable h/w rendering 126 char property[PROPERTY_VALUE_MAX]; 127 if (property_get("debug.sf.hw", property, NULL) > 0) { 128 if (atoi(property) == 0) { 129 LOGW("H/W composition disabled"); 130 attribs[2] = EGL_CONFIG_CAVEAT; 131 attribs[3] = EGL_SLOW_CONFIG; 132 } 133 } 134 135 // TODO: all the extensions below should be queried through 136 // eglGetProcAddress(). 137 138 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 139 eglInitialize(display, NULL, NULL); 140 eglGetConfigs(display, NULL, 0, &numConfigs); 141 142 EGLConfig config; 143 status_t err = EGLUtils::selectConfigForNativeWindow( 144 display, attribs, mNativeWindow.get(), &config); 145 LOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); 146 147 EGLint r,g,b,a; 148 eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); 149 eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); 150 eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); 151 eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); 152 153 if (mNativeWindow->isUpdateOnDemand()) { 154 mFlags |= PARTIAL_UPDATES; 155 } 156 157 if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { 158 if (dummy == EGL_SLOW_CONFIG) 159 mFlags |= SLOW_CONFIG; 160 } 161 162 /* 163 * Create our main surface 164 */ 165 166 surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); 167 eglQuerySurface(display, surface, EGL_WIDTH, &mWidth); 168 eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); 169 170 if (mFlags & PARTIAL_UPDATES) { 171 // if we have partial updates, we definitely don't need to 172 // preserve the backbuffer, which may be costly. 173 eglSurfaceAttrib(display, surface, 174 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); 175 } 176 177 if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) { 178 if (dummy == EGL_BUFFER_PRESERVED) { 179 mFlags |= BUFFER_PRESERVED; 180 } 181 } 182 183 /* Read density from build-specific ro.sf.lcd_density property 184 * except if it is overridden by qemu.sf.lcd_density. 185 */ 186 if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) { 187 if (property_get("ro.sf.lcd_density", property, NULL) <= 0) { 188 LOGW("ro.sf.lcd_density not defined, using 160 dpi by default."); 189 strcpy(property, "160"); 190 } 191 } else { 192 /* for the emulator case, reset the dpi values too */ 193 mDpiX = mDpiY = atoi(property); 194 } 195 mDensity = atoi(property) * (1.0f/160.0f); 196 197 198 /* 199 * Create our OpenGL ES context 200 */ 201 202 203 EGLint contextAttributes[] = { 204#ifdef EGL_IMG_context_priority 205#ifdef HAS_CONTEXT_PRIORITY 206#warning "using EGL_IMG_context_priority" 207 EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, 208#endif 209#endif 210 EGL_NONE, EGL_NONE 211 }; 212 context = eglCreateContext(display, config, NULL, contextAttributes); 213 214 mDisplay = display; 215 mConfig = config; 216 mSurface = surface; 217 mContext = context; 218 mFormat = fbDev->format; 219 mPageFlipCount = 0; 220 221 /* 222 * Gather OpenGL ES extensions 223 */ 224 225 eglMakeCurrent(display, surface, surface, context); 226 227 GLExtensions& extensions(GLExtensions::getInstance()); 228 extensions.initWithGLStrings( 229 glGetString(GL_VENDOR), 230 glGetString(GL_RENDERER), 231 glGetString(GL_VERSION), 232 glGetString(GL_EXTENSIONS), 233 eglQueryString(display, EGL_VENDOR), 234 eglQueryString(display, EGL_VERSION), 235 eglQueryString(display, EGL_EXTENSIONS)); 236 237 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); 238 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims); 239 240 241#ifdef EGL_ANDROID_swap_rectangle 242 if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) { 243 if (eglSetSwapRectangleANDROID(display, surface, 244 0, 0, mWidth, mHeight) == EGL_TRUE) { 245 // This could fail if this extension is not supported by this 246 // specific surface (of config) 247 mFlags |= SWAP_RECTANGLE; 248 } 249 } 250 // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE 251 // choose PARTIAL_UPDATES, which should be more efficient 252 if (mFlags & PARTIAL_UPDATES) 253 mFlags &= ~SWAP_RECTANGLE; 254#endif 255 256 LOGI("EGL informations:"); 257 LOGI("# of configs : %d", numConfigs); 258 LOGI("vendor : %s", extensions.getEglVendor()); 259 LOGI("version : %s", extensions.getEglVersion()); 260 LOGI("extensions: %s", extensions.getEglExtension()); 261 LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); 262 LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); 263 264 LOGI("OpenGL informations:"); 265 LOGI("vendor : %s", extensions.getVendor()); 266 LOGI("renderer : %s", extensions.getRenderer()); 267 LOGI("version : %s", extensions.getVersion()); 268 LOGI("extensions: %s", extensions.getExtension()); 269 LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); 270 LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims); 271 LOGI("flags = %08x", mFlags); 272 273 // Unbind the context from this thread 274 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 275 276 277 // initialize the H/W composer 278 mHwc = new HWComposer(); 279 if (mHwc->initCheck() == NO_ERROR) { 280 mHwc->setFrameBuffer(mDisplay, mSurface); 281 } 282} 283 284HWComposer& DisplayHardware::getHwComposer() const { 285 return *mHwc; 286} 287 288/* 289 * Clean up. Throw out our local state. 290 * 291 * (It's entirely possible we'll never get here, since this is meant 292 * for real hardware, which doesn't restart.) 293 */ 294 295void DisplayHardware::fini() 296{ 297 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 298 eglTerminate(mDisplay); 299 overlay_control_close(mOverlayEngine); 300} 301 302void DisplayHardware::releaseScreen() const 303{ 304 DisplayHardwareBase::releaseScreen(); 305 if (mHwc->initCheck() == NO_ERROR) { 306 mHwc->release(); 307 } 308} 309 310void DisplayHardware::acquireScreen() const 311{ 312 DisplayHardwareBase::acquireScreen(); 313} 314 315uint32_t DisplayHardware::getPageFlipCount() const { 316 return mPageFlipCount; 317} 318 319status_t DisplayHardware::compositionComplete() const { 320 return mNativeWindow->compositionComplete(); 321} 322 323int DisplayHardware::getCurrentBufferIndex() const { 324 return mNativeWindow->getCurrentBufferIndex(); 325} 326 327void DisplayHardware::flip(const Region& dirty) const 328{ 329 checkGLErrors(); 330 331 EGLDisplay dpy = mDisplay; 332 EGLSurface surface = mSurface; 333 334#ifdef EGL_ANDROID_swap_rectangle 335 if (mFlags & SWAP_RECTANGLE) { 336 const Region newDirty(dirty.intersect(bounds())); 337 const Rect b(newDirty.getBounds()); 338 eglSetSwapRectangleANDROID(dpy, surface, 339 b.left, b.top, b.width(), b.height()); 340 } 341#endif 342 343 if (mFlags & PARTIAL_UPDATES) { 344 mNativeWindow->setUpdateRectangle(dirty.getBounds()); 345 } 346 347 mPageFlipCount++; 348 349 if (mHwc->initCheck() == NO_ERROR) { 350 mHwc->commit(); 351 } else { 352 eglSwapBuffers(dpy, surface); 353 } 354 checkEGLErrors("eglSwapBuffers"); 355 356 // for debugging 357 //glClearColor(1,0,0,0); 358 //glClear(GL_COLOR_BUFFER_BIT); 359} 360 361uint32_t DisplayHardware::getFlags() const 362{ 363 return mFlags; 364} 365 366void DisplayHardware::makeCurrent() const 367{ 368 eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); 369} 370 371void DisplayHardware::dump(String8& res) const 372{ 373 mNativeWindow->dump(res); 374} 375