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/copybit.h> 40 #include <hardware/overlay.h> 41 #include <hardware/gralloc.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 LOGE("GL error 0x%04x", int(error)); 55 } while(true); 56 } 57 58 static __attribute__((noinline)) 59 void checkEGLErrors(const char* token) 60 { 61 EGLint error = eglGetError(); 62 if (error && error != EGL_SUCCESS) { 63 LOGE("%s: EGL error 0x%04x (%s)", 64 token, int(error), EGLUtils::strerror(error)); 65 } 66 } 67 68 /* 69 * Initialize the display to the specified values. 70 * 71 */ 72 73 DisplayHardware::DisplayHardware( 74 const sp<SurfaceFlinger>& flinger, 75 uint32_t dpy) 76 : DisplayHardwareBase(flinger, dpy) 77 { 78 init(dpy); 79 } 80 81 DisplayHardware::~DisplayHardware() 82 { 83 fini(); 84 } 85 86 float DisplayHardware::getDpiX() const { return mDpiX; } 87 float DisplayHardware::getDpiY() const { return mDpiY; } 88 float DisplayHardware::getDensity() const { return mDensity; } 89 float DisplayHardware::getRefreshRate() const { return mRefreshRate; } 90 int DisplayHardware::getWidth() const { return mWidth; } 91 int DisplayHardware::getHeight() const { return mHeight; } 92 PixelFormat DisplayHardware::getFormat() const { return mFormat; } 93 uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; } 94 uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; } 95 96 void DisplayHardware::init(uint32_t dpy) 97 { 98 mNativeWindow = new FramebufferNativeWindow(); 99 framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); 100 101 mOverlayEngine = NULL; 102 hw_module_t const* module; 103 if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) { 104 overlay_control_open(module, &mOverlayEngine); 105 } 106 107 // initialize EGL 108 EGLint attribs[] = { 109 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 110 EGL_NONE, 0, 111 EGL_NONE 112 }; 113 114 // debug: disable h/w rendering 115 char property[PROPERTY_VALUE_MAX]; 116 if (property_get("debug.sf.hw", property, NULL) > 0) { 117 if (atoi(property) == 0) { 118 LOGW("H/W composition disabled"); 119 attribs[2] = EGL_CONFIG_CAVEAT; 120 attribs[3] = EGL_SLOW_CONFIG; 121 } 122 } 123 124 EGLint w, h, dummy; 125 EGLint numConfigs=0; 126 EGLSurface surface; 127 EGLContext context; 128 mFlags = CACHED_BUFFERS; 129 130 // TODO: all the extensions below should be queried through 131 // eglGetProcAddress(). 132 133 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 134 eglInitialize(display, NULL, NULL); 135 eglGetConfigs(display, NULL, 0, &numConfigs); 136 137 EGLConfig config; 138 status_t err = EGLUtils::selectConfigForNativeWindow( 139 display, attribs, mNativeWindow.get(), &config); 140 LOGE_IF(err, "couldn't find an EGLConfig matching the screen format"); 141 142 EGLint r,g,b,a; 143 eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); 144 eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); 145 eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); 146 eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); 147 148 /* 149 * Gather EGL extensions 150 */ 151 152 const char* const egl_extensions = eglQueryString( 153 display, EGL_EXTENSIONS); 154 155 LOGI("EGL informations:"); 156 LOGI("# of configs : %d", numConfigs); 157 LOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); 158 LOGI("version : %s", eglQueryString(display, EGL_VERSION)); 159 LOGI("extensions: %s", egl_extensions); 160 LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported"); 161 LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); 162 163 164 if (mNativeWindow->isUpdateOnDemand()) { 165 mFlags |= PARTIAL_UPDATES; 166 } 167 168 if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { 169 if (dummy == EGL_SLOW_CONFIG) 170 mFlags |= SLOW_CONFIG; 171 } 172 173 /* 174 * Create our main surface 175 */ 176 177 surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); 178 179 if (mFlags & PARTIAL_UPDATES) { 180 // if we have partial updates, we definitely don't need to 181 // preserve the backbuffer, which may be costly. 182 eglSurfaceAttrib(display, surface, 183 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); 184 } 185 186 if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) { 187 if (dummy == EGL_BUFFER_PRESERVED) { 188 mFlags |= BUFFER_PRESERVED; 189 } 190 } 191 192 eglQuerySurface(display, surface, EGL_WIDTH, &mWidth); 193 eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); 194 195 #ifdef EGL_ANDROID_swap_rectangle 196 if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) { 197 if (eglSetSwapRectangleANDROID(display, surface, 198 0, 0, mWidth, mHeight) == EGL_TRUE) { 199 // This could fail if this extension is not supported by this 200 // specific surface (of config) 201 mFlags |= SWAP_RECTANGLE; 202 } 203 } 204 // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE 205 // choose PARTIAL_UPDATES, which should be more efficient 206 if (mFlags & PARTIAL_UPDATES) 207 mFlags &= ~SWAP_RECTANGLE; 208 #endif 209 210 211 LOGI("flags : %08x", mFlags); 212 213 mDpiX = mNativeWindow->xdpi; 214 mDpiY = mNativeWindow->ydpi; 215 mRefreshRate = fbDev->fps; 216 217 /* Read density from build-specific ro.sf.lcd_density property 218 * except if it is overridden by qemu.sf.lcd_density. 219 */ 220 if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) { 221 if (property_get("ro.sf.lcd_density", property, NULL) <= 0) { 222 LOGW("ro.sf.lcd_density not defined, using 160 dpi by default."); 223 strcpy(property, "160"); 224 } 225 } else { 226 /* for the emulator case, reset the dpi values too */ 227 mDpiX = mDpiY = atoi(property); 228 } 229 mDensity = atoi(property) * (1.0f/160.0f); 230 231 232 /* 233 * Create our OpenGL ES context 234 */ 235 236 context = eglCreateContext(display, config, NULL, NULL); 237 238 /* 239 * Gather OpenGL ES extensions 240 */ 241 242 eglMakeCurrent(display, surface, surface, context); 243 const char* const gl_extensions = (const char*)glGetString(GL_EXTENSIONS); 244 const char* const gl_renderer = (const char*)glGetString(GL_RENDERER); 245 LOGI("OpenGL informations:"); 246 LOGI("vendor : %s", glGetString(GL_VENDOR)); 247 LOGI("renderer : %s", gl_renderer); 248 LOGI("version : %s", glGetString(GL_VERSION)); 249 LOGI("extensions: %s", gl_extensions); 250 251 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); 252 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims); 253 LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize); 254 LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims); 255 256 #if 0 257 // for drivers that don't have proper support for flushing cached buffers 258 // on gralloc unlock, uncomment this block and test for the specific 259 // renderer substring 260 if (strstr(gl_renderer, "<some vendor string>")) { 261 LOGD("Assuming uncached graphics buffers."); 262 mFlags &= ~CACHED_BUFFERS; 263 } 264 #endif 265 266 if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) { 267 mFlags |= NPOT_EXTENSION; 268 } 269 if (strstr(gl_extensions, "GL_OES_draw_texture")) { 270 mFlags |= DRAW_TEXTURE_EXTENSION; 271 } 272 #ifdef EGL_ANDROID_image_native_buffer 273 if (strstr( gl_extensions, "GL_OES_EGL_image") && 274 (strstr(egl_extensions, "EGL_KHR_image_base") || 275 strstr(egl_extensions, "EGL_KHR_image")) && 276 strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) { 277 mFlags |= DIRECT_TEXTURE; 278 } 279 #else 280 #warning "EGL_ANDROID_image_native_buffer not supported" 281 #endif 282 283 284 // Unbind the context from this thread 285 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 286 287 mDisplay = display; 288 mConfig = config; 289 mSurface = surface; 290 mContext = context; 291 mFormat = fbDev->format; 292 mPageFlipCount = 0; 293 } 294 295 /* 296 * Clean up. Throw out our local state. 297 * 298 * (It's entirely possible we'll never get here, since this is meant 299 * for real hardware, which doesn't restart.) 300 */ 301 302 void DisplayHardware::fini() 303 { 304 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 305 eglTerminate(mDisplay); 306 overlay_control_close(mOverlayEngine); 307 } 308 309 void DisplayHardware::releaseScreen() const 310 { 311 DisplayHardwareBase::releaseScreen(); 312 } 313 314 void DisplayHardware::acquireScreen() const 315 { 316 DisplayHardwareBase::acquireScreen(); 317 } 318 319 uint32_t DisplayHardware::getPageFlipCount() const { 320 return mPageFlipCount; 321 } 322 323 status_t DisplayHardware::compositionComplete() const { 324 return mNativeWindow->compositionComplete(); 325 } 326 327 void 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 eglSwapBuffers(dpy, surface); 349 checkEGLErrors("eglSwapBuffers"); 350 351 // for debugging 352 //glClearColor(1,0,0,0); 353 //glClear(GL_COLOR_BUFFER_BIT); 354 } 355 356 uint32_t DisplayHardware::getFlags() const 357 { 358 return mFlags; 359 } 360 361 void DisplayHardware::makeCurrent() const 362 { 363 eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); 364 } 365