android屏幕旋转显示流程
2016-10-20 16:17
519 查看
PAD默认屏幕显示方向是竖着显示,改成默认横屏显示需要将屏幕的默认显示方向顺时针旋转90度.
android显示系统的核心是surfaceflinger,它为所有的应用程序提供显示服务,它能够将各种应用程序的2D,3D surface进行组合,合并最终得到的一个main surface数据送入framebuffer,显示的翻转和旋转也是由surfaceflinger完成的,我们大致分析下surfaceflinger的旋转流程:
1.surfaceflinger启动后首先进行初始化操作,设置surfaceflinger的相关属性并创建了DisplayDevice对象
setMTKProperties()中会设置surfaceflinger的相关属性:
2.DisplayDevice中会调用显示的旋转函数setProjection()
接着调用DisplayDevice类的orientationToTransfrom()方法构造成一个变换矩阵R,然后得到mGlobalTransform这个全局变换矩阵,最后通过mGlobalTransform.transform()这个方法进行显示的旋转
这里调用Transform::set()方法设置矩阵,有兴趣可以深入分析
android显示系统的核心是surfaceflinger,它为所有的应用程序提供显示服务,它能够将各种应用程序的2D,3D surface进行组合,合并最终得到的一个main surface数据送入framebuffer,显示的翻转和旋转也是由surfaceflinger完成的,我们大致分析下surfaceflinger的旋转流程:
1.surfaceflinger启动后首先进行初始化操作,设置surfaceflinger的相关属性并创建了DisplayDevice对象
void SurfaceFlinger::init() { ... #ifdef MTK_AOSP_ENHANCEMENT // make sure 3D init success if (mEGLContext == EGL_NO_CONTEXT) { ALOGE("FATAL: couldn't create EGLContext"); delete mHwc; eglTerminate(mEGLDisplay); exit(0); } // init properties setting first setMTKProperties(); //设置MTK相关属性 #else LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, "couldn't create EGLContext"); #endif ... // initialize our non-virtual displays for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); // set-up the displays that are already connected if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { // All non-virtual displays are currently considered secure. bool isSecure = true; createBuiltinDisplayLocked(type); wp<IBinder> token = mBuiltinDisplays[i]; sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc()); sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, consumer); int32_t hwcId = allocateHwcDisplayId(type); sp<DisplayDevice> hw = new DisplayDevice(this, //初始化各个DisplayDevice对象 type, hwcId, mHwc->getFormat(hwcId), isSecure, token, fbs, producer, mRenderEngine->getEGLConfig()); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don't get blank/unblank requests // for displays other than the main display, so we always // assume a connected display is unblanked. ALOGD("marking display %zu as acquired/unblanked", i); hw->setPowerMode(HWC_POWER_MODE_NORMAL); } mDisplays.add(token, hw); } } }
setMTKProperties()中会设置surfaceflinger的相关属性:
void SurfaceFlinger::setMTKProperties(String8 &result) { ... // get info for panel physical rotation property_get("ro.sf.hwrotation", value, "0"); sPropertiesState.mHwRotation = atoi(value); snprintf(buffer, sizeof(buffer), " ro.sf.hwrotation (mHwRotation): %d\n", sPropertiesState.mHwRotation); result.append(buffer); ... }此处会读取ro.sf.hwrotation系统属性,这个系统属性决定了显示屏的初始旋转方向,并保存到全局变量sPropertiesState.mHwRotation中
2.DisplayDevice中会调用显示的旋转函数setProjection()
DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, int format, bool isSecure, const wp<IBinder>& displayToken, const sp<DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer, EGLConfig config)( <span style="font-family: Arial, Helvetica, sans-serif;">... </span><pre code_snippet_id="1939821" snippet_file_name="blog_20161020_4_9852155" name="code" class="cpp">#ifdef MTK_AOSP_ENHANCEMENT mHwOrientation = DisplayState::eOrientationDefault; //读取默认的显示屏方向 // Name the display. The name will be replaced shortly if the display // was created with createDisplay(). switch (mType) { case DISPLAY_PRIMARY: mDisplayName = "Built-in Screen"; #ifdef MTK_AOSP_ENHANCEMENT switch (mFlinger->sPropertiesState.mHwRotation) { //读取显示屏初始旋转方向 case 90: mHwOrientation = DisplayState::eOrientation90; break; case 180: mHwOrientation = DisplayState::eOrientation180; break; case 270: mHwOrientation = DisplayState::eOrientation270; break; } #endif break; case DISPLAY_EXTERNAL: mDisplayName = "HDMI Screen"; break; default: mDisplayName = "Virtual Screen"; // e.g. Overlay #n break; } // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); //设置显示屏初始旋转方向 }
void DisplayDevice::setProjection(int orientation, const Rect& newViewport, const Rect& newFrame) { Rect viewport(newViewport); Rect frame(newFrame); const int w = mDisplayWidth; const int h = mDisplayHeight; Transform R; DisplayDevice::orientationToTransfrom(orientation, w, h, &R); if (!frame.isValid()) { // the destination frame can be invalid if it has never been set, // in that case we assume the whole display frame. frame = Rect(w, h); } if (viewport.isEmpty()) { // viewport can be invalid if it has never been set, in that case // we assume the whole display size. // it's also invalid to have an empty viewport, so we handle that // case in the same way. viewport = Rect(w, h); if (R.getOrientation() & Transform::ROT_90) { // viewport is always specified in the logical orientation // of the display (ie: post-rotation). swap(viewport.right, viewport.bottom); } } dirtyRegion.set(getBounds()); #ifdef MTK_AOSP_ENHANCEMENT // for boot animation black screen issue if ((false == mFlinger->getBootFinished()) && (DISPLAY_PRIMARY == mType)) { ALOGI("[%s] clear DisplayDevice(type:%d) dirty region while booting", __FUNCTION__, mType); dirtyRegion.clear(); } #endif Transform TL, TP, S; float src_width = viewport.width(); float src_height = viewport.height(); float dst_width = frame.width(); float dst_height = frame.height(); if (src_width != dst_width || src_height != dst_height) { float sx = dst_width / src_width; float sy = dst_height / src_height; S.set(sx, 0, 0, sy); } float src_x = viewport.left; float src_y = viewport.top; float dst_x = frame.left; float dst_y = frame.top; TL.set(-src_x, -src_y); TP.set(dst_x, dst_y); #ifdef MTK_AOSP_ENHANCEMENT // need to take care of HW rotation for mGlobalTransform // for case if the panel is not installed align with device orientation if (DisplayState::eOrientationDefault != mHwOrientation) { DisplayDevice::orientationToTransfrom( (orientation + mHwOrientation) % (DisplayState::eOrientation270 + 1), w, h, &R); } #endif // The viewport and frame are both in the logical orientation. // Apply the logical translation, scale to physical size, apply the // physical translation and finally rotate to the physical orientation. mGlobalTransform = R * TP * S * TL; const uint8_t type = mGlobalTransform.getType(); mNeedsFiltering = (!mGlobalTransform.preserveRects() || (type >= Transform::SCALE)); mScissor = mGlobalTransform.transform(viewport); if (mScissor.isEmpty()) { mScissor = getBounds(); } mOrientation = orientation; mViewport = viewport; mFrame = frame; }
接着调用DisplayDevice类的orientationToTransfrom()方法构造成一个变换矩阵R,然后得到mGlobalTransform这个全局变换矩阵,最后通过mGlobalTransform.transform()这个方法进行显示的旋转
status_t DisplayDevice::orientationToTransfrom( int orientation, int w, int h, Transform* tr) { uint32_t flags = 0; switch (orientation) { case DisplayState::eOrientationDefault: flags = Transform::ROT_0; break; case DisplayState::eOrientation90: flags = Transform::ROT_90; break; case DisplayState::eOrientation180: flags = Transform::ROT_180; break; case DisplayState::eOrientation270: flags = Transform::ROT_270; break; default: return BAD_VALUE; } tr->set(flags, w, h); return NO_ERROR; }
这里调用Transform::set()方法设置矩阵,有兴趣可以深入分析
相关文章推荐
- Android 系统设置中显示设置之屏幕旋转和字体设置篇
- Android 6.0 屏幕旋转系统流程分析
- Android 系统设置中显示设置之屏幕旋转和字体设置篇
- Android 系统设置中显示设置之屏幕旋转和字体设置篇
- Android 7.1 ActivityManagerService 屏幕旋转流程分析 (四)
- Android 屏幕处于横屏状态 旋转180度界面切换显示
- android自动屏幕旋转流程分析
- Android屏幕显示旋转180度解决方法
- Android 7.1 WindowManagerService 屏幕旋转流程分析 (二)
- Android 7.1 WindowManagerService 屏幕旋转流程分析 (三)
- Android 7.1 屏幕旋转流程分析
- Android开发OpenGL ES的流程,从着色器编写到显示在屏幕上
- 代码流程分析一:Settings中默认值的流程-显示-自动旋转屏幕
- android自动屏幕旋转流程分析
- android自动屏幕旋转流程分析
- Android 屏幕旋转事件流程分析
- 让android程序根据重力感应旋转屏幕(支持4个方向旋转)
- android模拟机切换屏幕显示
- android 屏幕旋转 重新调用onCreate的解决方法
- 关于ToolRotate——Android屏幕方向旋转的根源